Initial Contribution
Signed-off-by: Vinay Vishal <vinay.vishal@oracle.com>
diff --git a/nucleus/core/kernel/src/main/java/com/sun/appserv/.gitkeep_empty_dir b/nucleus/core/kernel/src/main/java/com/sun/appserv/.gitkeep_empty_dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/appserv/.gitkeep_empty_dir
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminAdapter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminAdapter.java
new file mode 100644
index 0000000..012891c
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminAdapter.java
@@ -0,0 +1,700 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.admin.remote.RemoteRestAdminCommand;
+import com.sun.enterprise.config.serverbeans.*;
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.module.common_impl.LogHelper;
+import com.sun.enterprise.universal.GFBase64Decoder;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import com.sun.enterprise.util.uuid.UuidGenerator;
+import com.sun.enterprise.util.uuid.UuidGeneratorImpl;
+import com.sun.enterprise.v3.admin.adapter.AdminEndpointDecider;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URLDecoder;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+import org.glassfish.admin.payload.PayloadImpl;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.container.Adapter;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.api.event.RestrictTo;
+import org.glassfish.grizzly.http.Cookie;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.StaticHttpHandler;
+import org.glassfish.grizzly.http.util.CookieSerializerUtils;
+import org.glassfish.grizzly.http.util.HttpStatus;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.api.AdminAccessController;
+import org.glassfish.internal.api.Privacy;
+import org.glassfish.internal.api.RemoteAdminAccessException;
+import org.glassfish.internal.api.ServerContext;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.glassfish.server.ServerEnvironmentImpl;
+
+/**
+ * Listen to admin commands...
+ * @author dochez
+ */
+public abstract class AdminAdapter extends StaticHttpHandler implements Adapter, PostConstruct, EventListener {
+
+ public final static String VS_NAME="__asadmin";
+ public final static String PREFIX_URI = "/" + VS_NAME;
+ private final static LocalStringManagerImpl adminStrings = new LocalStringManagerImpl(AdminAdapter.class);
+ private final static Logger aalogger = KernelLoggerInfo.getLogger();
+ private static final GFBase64Decoder decoder = new GFBase64Decoder();
+ private static final String BASIC = "Basic ";
+
+ private static final String SET_COOKIE_HEADER = "Set-Cookie";
+
+ public static final String SESSION_COOKIE_NAME = "JSESSIONID";
+
+ public static final int MAX_AGE = 86400 ;
+
+ public static final String ASADMIN_PATH="/__asadmin";
+
+ private static final String QUERY_STRING_SEPARATOR = "&";
+
+ @Inject
+ ModulesRegistry modulesRegistry;
+
+ @Inject
+ CommandRunnerImpl commandRunner;
+
+ @Inject
+ ServerEnvironmentImpl env;
+
+ @Inject
+ Events events;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ private AdminEndpointDecider epd = null;
+
+ @Inject
+ ServerContext sc;
+
+ @Inject
+ ServiceLocator habitat;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ volatile AdminService as;
+
+ @Inject
+ volatile Domain domain;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ private volatile Server server;
+
+ @Inject
+ AdminAccessController authenticator;
+
+ final Class<? extends Privacy> privacyClass;
+
+ private boolean isRegistered = false;
+
+ CountDownLatch latch = new CountDownLatch(1);
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected AdminAdapter(Class<? extends Privacy> privacyClass) {
+ super((Set) null);
+ this.privacyClass = privacyClass;
+ }
+
+ @Override
+ public final HttpHandler getHttpService() {
+ return this;
+ }
+
+ @Override
+ public void postConstruct() {
+ events.register(this);
+
+ epd = new AdminEndpointDecider(config);
+ addDocRoot(env.getProps().get(SystemPropertyConstants.INSTANCE_ROOT_PROPERTY) + "/asadmindocroot/");
+ }
+
+ /**
+ * Call the service method, and notify all listeners
+ *
+ * @exception Exception if an error happens during handling of
+ * the request. Common errors are:
+ * <ul><li>IOException if an input/output error occurs and we are
+ * processing an included servlet (otherwise it is swallowed and
+ * handled by the top level error handler mechanism)
+ * <li>ServletException if a servlet throws an exception and
+ * we are processing an included servlet (otherwise it is swallowed
+ * and handled by the top level error handler mechanism)
+ * </ul>
+ * Tomcat should be able to handle and log any other exception ( including
+ * runtime exceptions )
+ */
+ @Override
+ public void onMissingResource(Request req, Response res) {
+
+ LogHelper.getDefaultLogger().log(Level.FINER, "Received something on {0}", req.getRequestURI());
+ LogHelper.getDefaultLogger().log(Level.FINER, "QueryString = {0}", req.getQueryString());
+
+ HttpStatus statusCode = HttpStatus.OK_200;
+
+ String requestURI = req.getRequestURI();
+ /* if (requestURI.startsWith("/__asadmin/ADMINGUI")) {
+ super.service(req, res);
+
+ }*/
+ ActionReport report = getClientActionReport(requestURI, req);
+ // remove the qualifier if necessary
+ if (requestURI.indexOf('.')!=-1) {
+ requestURI = requestURI.substring(0, requestURI.indexOf('.'));
+ }
+
+ Payload.Outbound outboundPayload = PayloadImpl.Outbound.newInstance();
+
+ try {
+ if (!latch.await(20L, TimeUnit.SECONDS)) {
+ report = getClientActionReport(req.getRequestURI(), req);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage("V3 cannot process this command at this time, please wait");
+ } else {
+
+ final Subject s = (authenticator == null) ? null : authenticator.loginAsAdmin(req);
+ if (s == null) {
+ reportAuthFailure(res, report, "adapter.auth.userpassword",
+ "Invalid user name or password",
+ HttpURLConnection.HTTP_UNAUTHORIZED,
+ "WWW-Authenticate", "BASIC");
+ return;
+ }
+ report = doCommand(requestURI, req, report, outboundPayload, s);
+ }
+ } catch (ProcessHttpCommandRequestException reqEx) {
+ report = reqEx.getReport();
+ statusCode = reqEx.getResponseStatus();
+ } catch(InterruptedException e) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage("V3 cannot process this command at this time, please wait");
+ } catch (Exception e) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage("Exception while processing command: " + e);
+ }
+
+ try {
+ res.setStatus(statusCode);
+ /*
+ * Format the command result report into the first part (part #0) of
+ * the outbound payload and set the response's content type based
+ * on the payload's. If the report is the only part then the
+ * stream will be written as content type text/something and
+ * will contain only the report. If the payload already has
+ * content - such as files to be downloaded, for example - then the
+ * content type of the payload reflects its multi-part nature and
+ * an implementation-specific content type will be set in the response.
+ */
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+ report.writeReport(baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ final Properties reportProps = new Properties();
+ reportProps.setProperty("data-request-type", "report");
+ outboundPayload.addPart(0, report.getContentType(), "report",
+ reportProps, bais);
+ res.setContentType(outboundPayload.getContentType());
+ String commandName = req.getRequestURI().substring(getContextRoot().length() + 1);
+ //Check session routing for commands that have @ExecuteOn(RuntimeType.SINGLE_INSTANCE)
+ if ( isSingleInstanceCommand(commandName)) {
+ res.addHeader(SET_COOKIE_HEADER, getCookieHeader(req));
+ }
+ outboundPayload.writeTo(res.getOutputStream());
+ res.getOutputStream().flush();
+ res.finish();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * This method checks if the request has a Cookie header and
+ * if the instance name serving the request is the same as the
+ * jvmRoute information
+ * @param req Request to examine the Cookie header
+ * @return true if the Cookie header is set and the jvmRoute information is the same as
+ * the instance serving the request , false otherwise
+ *
+ */
+ public boolean hasCookieHeader(Request req) {
+
+ String[] nameValuePair = getJSESSIONIDHeaders(req);
+ if (nameValuePair != null ) {
+ String headerValue = nameValuePair[1];
+
+ int index = headerValue.lastIndexOf('.');
+ return headerValue.substring(index+1)
+ .equals(server.getName())? true : false;
+
+ }
+ return false;
+ }
+
+ /**
+ * This method will return the Cookie header with name JSESSIONID="..."
+ * @param req The request which may contain cookie headers
+ * @return cookie header
+ */
+ public String[] getJSESSIONIDHeaders(Request req) {
+ for (String header : req.getHeaders("Cookie")){
+
+ String cookieHeaders[] = header.trim().split(";");
+ for (String cookieHeader:cookieHeaders) {
+ String[] nameValuePair = cookieHeader.trim().split("=");
+ if (nameValuePair[0].equals(SESSION_COOKIE_NAME)) {
+ return nameValuePair;
+ }
+ }
+
+ }
+ return null;
+
+ }
+
+ /**
+ * This method checks if this command has @ExecuteOn annotation with
+ * RuntimeType.SINGle_INSTANCE
+ * @param commandName the command which is executed
+ * @return true only if @ExecuteOn has RuntimeType.SINGLE_INSTANCE false for
+ * other cases
+ */
+ public boolean isSingleInstanceCommand(String commandName) {
+
+ CommandModel model = commandRunner.getModel(getScope(commandName),getCommandAfterScope(commandName),aalogger) ;
+ if (model != null ) {
+ ExecuteOn executeOn = model.getClusteringAttributes();
+ if ((executeOn != null) && (executeOn.value().length ==1) &&
+ executeOn.value()[0].equals(RuntimeType.SINGLE_INSTANCE)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This will create a unique SessionId, Max-Age,Version,Path to be added to the Set-Cookie header
+ * @return Set-Cookie2 header
+ */
+ public String getCookieHeader(Request req) {
+ String sessionId = null;
+ // If the request has a Cookie header and
+ // there is no failover then send back the same
+ // JSESSIONID in Set-Cookie2 header
+ if ( hasCookieHeader(req)) {
+ sessionId = getJSESSIONIDHeaders(req)[1];
+ } else {
+ //There is no Cookie header in request so generate a new JSESSIONID or
+ //failover has occured in which case you can generate a new JSESSIONID
+ sessionId = createSessionId();
+ }
+ StringBuilder sb = new StringBuilder();
+ final Cookie cookie = new Cookie(SESSION_COOKIE_NAME, sessionId);
+ cookie.setMaxAge(MAX_AGE);
+ cookie.setPath(ASADMIN_PATH);
+ cookie.setVersion(1);
+ CookieSerializerUtils.serializeServerCookie(sb, true, false, false, cookie);
+ return sb.toString();
+
+ }
+
+ /**
+ * This will create a new sessionId and add the server name as a jvmroute information to it
+ * @return String to be used for the JSESSIONID Set-Cookie2 header
+ */
+
+ public String createSessionId(){
+ UuidGenerator uuidGenerator = new UuidGeneratorImpl();
+ StringBuffer sessionBuf = new StringBuffer();
+ String sessionId = uuidGenerator.generateUuid();
+ sessionBuf.append(sessionId).append('.').append(server.getName());
+ return sessionBuf.toString();
+ }
+
+ public AdminAccessController.Access authenticate(Request req) throws Exception {
+ /*
+ * At this point, this method should be obsolete. But in case it
+ * comes back to life it now conforms to the new API for loginAsAdmin.
+ * That is, loginAsAdmin throws a RemoteAdminAccessException if the
+ * request is remote but secure admin is disabled and it throws a
+ * LoginException if the user is not a legitimate administrator.
+ * Further, loginAsAdmin now does nothing regarding full vs. read-only
+ * access; those decisions are made during authorization of particular
+ * commands.
+ */
+ try {
+ authenticator.loginAsAdmin(req);
+ return (env.isDas() ? AdminAccessController.Access.FULL : AdminAccessController.Access.READONLY);
+ } catch (RemoteAdminAccessException ex) {
+ return AdminAccessController.Access.FORBIDDEN;
+ } catch (LoginException ex) {
+ return AdminAccessController.Access.NONE;
+ }
+ }
+
+
+ /** A convenience method to extract user name from a request. It assumes the HTTP Basic Auth.
+ *
+ * @param req instance of Request
+ * @return a two-element string array. If Auth header exists and can be correctly decoded, returns the user name
+ * and password as the two elements. If any error occurs or if the header does not exist, returns an array with
+ * two blank strings. Never returns a null.
+ * @throws IOException in case of error with decoding the buffer (HTTP basic auth)
+ */
+ public static String[] getUserPassword(Request req) throws IOException {
+ //implementation note: other adapters make use of this method
+ String authHeader = req.getHeader("Authorization");
+ if (authHeader == null) {
+ return new String[]{"", ""};
+ }
+ String enc = authHeader.substring(BASIC.length());
+ String dec = new String(decoder.decodeBuffer(enc));
+ int i = dec.indexOf(':');
+ if (i < 0)
+ return new String[] { "", "" };
+ return new String[] { dec.substring(0, i), dec.substring(i + 1) };
+ }
+
+ private void reportAuthFailure(final Response res,
+ final ActionReport report,
+ final String msgKey,
+ final String msg,
+ final int httpStatus,
+ final String headerName,
+ final String headerValue) throws IOException {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ final String messageForResponse = adminStrings.getLocalString(msgKey, msg);
+ report.setMessage(messageForResponse);
+ report.setActionDescription("Authentication error");
+ res.setStatus(httpStatus, messageForResponse);
+ if (headerName != null) {
+ res.setHeader(headerName, headerValue);
+ }
+ res.setContentType(report.getContentType());
+ report.writeReport(res.getOutputStream());
+ res.getOutputStream().flush();
+ res.finish();
+ }
+
+ private ActionReport getClientActionReport(String requestURI, Request req) {
+
+
+ ActionReport report=null;
+
+ // first we look at the command extension (ie list-applications.[json | html | mf]
+ if (requestURI.indexOf('.')!=-1) {
+ String qualifier = requestURI.substring(requestURI.indexOf('.')+1);
+ report = habitat.getService(ActionReport.class, qualifier);
+ } else {
+ String userAgent = req.getHeader("User-Agent");
+ if (userAgent!=null)
+ report = habitat.getService(ActionReport.class, userAgent.substring(userAgent.indexOf('/')+1));
+ if (report==null) {
+ String accept = req.getHeader("Accept");
+ if (accept!=null) {
+ StringTokenizer st = new StringTokenizer(accept, ",");
+ while (report==null && st.hasMoreElements()) {
+ final String scheme=st.nextToken();
+ report = habitat.getService(ActionReport.class, scheme.substring(scheme.indexOf('/')+1));
+ }
+ }
+ }
+ }
+ if (report==null) {
+ // get the default one.
+ report = habitat.getService(ActionReport.class, "html");
+ }
+ return report;
+ }
+
+ protected abstract boolean validatePrivacy(AdminCommand command);
+
+ private ActionReport doCommand(String requestURI, Request req, ActionReport report,
+ Payload.Outbound outboundPayload, Subject subject) throws ProcessHttpCommandRequestException {
+
+ if (!requestURI.startsWith(getContextRoot())) {
+ String msg = adminStrings.getLocalString("adapter.panic",
+ "Wrong request landed in AdminAdapter {0}", requestURI);
+ report.setMessage(msg);
+ LogHelper.getDefaultLogger().info(msg);
+ return report;
+ }
+
+ // wbn handle no command and no slash-suffix
+ String command ="";
+ if (requestURI.length() > getContextRoot().length() + 1) {
+ command = requestURI.substring(getContextRoot().length() + 1);
+ }
+
+ String scope = getScope(command);
+ command = getCommandAfterScope(command);
+
+ String qs = req.getQueryString();
+ final ParameterMap parameters = extractParameters(qs);
+ String passwordOptions = req.getHeader("X-passwords");
+ if (passwordOptions != null) {
+ decodePasswords(parameters, passwordOptions);
+ }
+
+ try {
+ Payload.Inbound inboundPayload = PayloadImpl.Inbound
+ .newInstance(req.getContentType(), req.getInputStream());
+ if (aalogger.isLoggable(Level.FINE)) {
+ aalogger.log(Level.FINE, "***** AdminAdapter {0} *****", req.getMethod());
+ }
+ AdminCommand adminCommand = commandRunner.getCommand(scope, command, report, aalogger);
+ if (adminCommand==null) {
+ // maybe commandRunner already reported the failure?
+ if (report.getActionExitCode() == ActionReport.ExitCode.FAILURE)
+ return report;
+ String message =
+ adminStrings.getLocalString("adapter.command.notfound",
+ "Command {0} not found", command);
+ // cound't find command, not a big deal
+ aalogger.log(Level.FINE, message);
+ report.setMessage(message);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return report;
+ }
+ //Validate admin command eTag
+ String modelETag = req.getHeader(RemoteRestAdminCommand.COMMAND_MODEL_MATCH_HEADER);
+ if (modelETag != null && !commandRunner.validateCommandModelETag(adminCommand, modelETag)) {
+ String message =
+ adminStrings.getLocalString("commandmodel.etag.invalid",
+ "Cached command model for command {0} is invalid.", command);
+ aalogger.log(Level.FINE, message);
+ report.setMessage(message);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ throw new ProcessHttpCommandRequestException(report, HttpStatus.PRECONDITION_FAILED_412);
+ }
+ //Execute
+ if (validatePrivacy(adminCommand)) {
+ //if (adminCommand.getClass().getAnnotation(Visibility.class).privacy().equals(visibility.privacy())) {
+ // todo : needs to be changed, we should reuse adminCommand
+ CommandRunner.CommandInvocation inv = commandRunner.getCommandInvocation(scope, command, report, subject,parameters.containsKey("notify"));
+ inv.parameters(parameters).inbound(inboundPayload).outbound(outboundPayload).execute();
+ try {
+ // note it has become extraordinarily difficult to change the reporter!
+ CommandRunnerImpl.ExecutionContext inv2 = (CommandRunnerImpl.ExecutionContext) inv;
+ report = inv2.report();
+ }
+ catch(Exception e) {
+ }
+ } else {
+ report.failure( aalogger,
+ adminStrings.getLocalString("adapter.wrongprivacy",
+ "Command {0} does not have {1} visibility",
+ command, privacyClass.getSimpleName().toLowerCase(Locale.ENGLISH)),
+ null);
+ return report;
+
+ }
+ } catch (ProcessHttpCommandRequestException reqEx) {
+ throw reqEx;
+ } catch (Throwable t) {
+ /*
+ * Must put the error information into the report
+ * for the client to see it.
+ */
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(t);
+ report.setMessage(t.getLocalizedMessage());
+ report.setActionDescription("Last-chance AdminAdapter exception handler");
+ }
+ return report;
+ }
+
+ /**
+ * Finish the response and recycle the request/response tokens. Base on
+ * the connection header, the underlying socket transport will be closed
+ */
+ public void afterService(Request req, Response res) throws Exception {
+ }
+
+ /**
+ * Notify all container event listeners that a particular event has
+ * occurred for this Adapter. The default implementation performs
+ * this notification synchronously using the calling thread.
+ *
+ * @param type Event type
+ * @param data Event data
+ */
+ public void fireAdapterEvent(String type, Object data) {
+ }
+
+ /**
+ * decode the parameters that were passed in the X-Passwords header
+ *
+ * @params requestString value of the X-Passwords header
+ * @returns a decoded requestString
+ */
+ void decodePasswords(ParameterMap pmap, final String requestString) {
+ StringTokenizer stoken = new StringTokenizer(requestString == null ? "" : requestString, QUERY_STRING_SEPARATOR);
+ while (stoken.hasMoreTokens()) {
+ String token = stoken.nextToken();
+ if (token.indexOf("=") == -1)
+ continue;
+ String paramName = token.substring(0, token.indexOf("="));
+ String value = token.substring(token.indexOf("=") + 1);
+
+ try {
+ value = URLDecoder.decode(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ aalogger.log(Level.WARNING, KernelLoggerInfo.cantDecodeParameter,
+ new Object[] { paramName, value });
+ continue;
+ }
+
+ try {
+ value = new String(decoder.decodeBuffer(value));
+ } catch (IOException e) {
+ aalogger.log(Level.WARNING, KernelLoggerInfo.cantDecodeParameter,
+ new Object[] { paramName, value });
+ continue;
+ }
+ pmap.add(paramName, value);
+ }
+
+ }
+
+ /**
+ * extract parameters from URI and save it in ParameterMap obj
+ *
+ * @params requestString string URI to extract
+ *
+ * @returns ParameterMap
+ */
+ ParameterMap extractParameters(final String requestString) {
+ // extract parameters...
+ final ParameterMap parameters = new ParameterMap();
+ StringTokenizer stoken = new StringTokenizer(requestString == null ? "" : requestString, QUERY_STRING_SEPARATOR);
+ while (stoken.hasMoreTokens()) {
+ String token = stoken.nextToken();
+ if (token.indexOf("=") == -1)
+ continue;
+ String paramName = token.substring(0, token.indexOf("="));
+ String value = token.substring(token.indexOf("=") + 1);
+ try {
+ value = URLDecoder.decode(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ aalogger.log(Level.WARNING, KernelLoggerInfo.cantDecodeParameter,
+ new Object[] {paramName, value});
+ }
+
+ parameters.add(paramName, value);
+ }
+
+ // Dump parameters...
+ if (aalogger.isLoggable(Level.FINER)) {
+ for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
+ for (String v : entry.getValue())
+ aalogger.log(Level.FINER, "Key {0} = {1}", new Object[]{entry.getKey(), v});
+ }
+ }
+ return parameters;
+ }
+
+ @Override
+ public void event(@RestrictTo(EventTypes.SERVER_READY_NAME) Event event) {
+ if (event.is(EventTypes.SERVER_READY)) {
+ latch.countDown();
+ aalogger.fine("Ready to receive administrative commands");
+ }
+ //the count-down does not start if any other event is received
+ }
+
+
+ @Override
+ public int getListenPort() {
+ return epd.getListenPort();
+ }
+
+ @Override
+ public InetAddress getListenAddress() {
+ return epd.getListenAddress();
+ }
+
+ @Override
+ public List<String> getVirtualServers() {
+ return epd.getAsadminHosts();
+ }
+
+ /**
+ * Checks whether this adapter has been registered as a network endpoint.
+ */
+ @Override
+ public boolean isRegistered() {
+ return isRegistered;
+ }
+
+ /**
+ * Marks this adapter as having been registered or unregistered as a
+ * network endpoint
+ */
+ @Override
+ public void setRegistered(boolean isRegistered) {
+ this.isRegistered = isRegistered;
+ }
+
+ /**
+ * A command is defined in a particular scope by
+ * using a prefix on the command service names, as in @Service(name="ascope/mycommand")
+ * This method gets the scope for a command which is "ascope/"
+ * for the above example
+ * @param command The command to be executed
+ * @return the scope for a command
+ */
+ private String getScope(String command) {
+ int ci = command.indexOf("/");
+ return (ci != -1) ? command.substring(0, ci + 1) : null;
+ }
+
+
+ /**
+ * This method gets the command after the scope string
+ * as defined for a command like this @Service(name="ascope/mycommand")
+ * @param command The command to be executed
+ * @return the shortened command after the scope ie "mycommand"
+ * for the above example
+ */
+ private String getCommandAfterScope(String command) {
+ int ci = command.indexOf("/");
+ return (ci != -1) ? command = command.substring(ci + 1) : command;
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminCommandInstanceImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminCommandInstanceImpl.java
new file mode 100644
index 0000000..cd9352b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminCommandInstanceImpl.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.admin.event.AdminCommandEventBrokerImpl;
+import com.sun.enterprise.admin.remote.AdminCommandStateImpl;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.ActionReport.ExitCode;
+import org.glassfish.api.admin.AdminCommandEventBroker;
+import org.glassfish.api.admin.Job;
+import org.glassfish.api.admin.CommandProgress;
+import org.glassfish.api.admin.Payload;
+import org.glassfish.api.admin.progress.JobInfo;
+import org.glassfish.api.admin.progress.JobPersistence;
+import org.glassfish.internal.api.Globals;
+import org.glassfish.security.services.common.SubjectUtil;
+
+import javax.security.auth.Subject;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Date;
+import java.util.List;
+import org.glassfish.api.admin.ParameterMap;
+
+/** Represents running (or finished) command instance.
+ *
+ *
+ * @author Martin Mares
+ * @author Bhakti Mehta
+ */
+
+public class AdminCommandInstanceImpl extends AdminCommandStateImpl implements Job {
+
+ private static final long serialVersionUID = 1L;
+
+// private final static LocalStringManagerImpl adminStrings = new LocalStringManagerImpl(AdminCommandInstanceImpl.class);
+
+ private CommandProgress commandProgress;
+ private transient Payload.Outbound payload;
+ private transient AdminCommandEventBroker broker;
+
+ private final long executionDate;
+
+ private final String commandName;
+
+ private List<String> subjectUsernames;
+
+ private final String scope;
+
+ private boolean isManagedJob;
+
+ private File jobsFile;
+
+ private long completionDate;
+
+ private ParameterMap parameters;
+
+ private boolean failToRetryable;
+
+ protected AdminCommandInstanceImpl(String id, String name, String commandScope, Subject sub, boolean managedJob, ParameterMap parameters) {
+ super(id);
+ this.broker = new AdminCommandEventBrokerImpl();
+ this.executionDate = new Date().getTime();
+ this.commandName = name;
+ this.scope= commandScope;
+ isManagedJob = managedJob;
+ this.subjectUsernames = SubjectUtil.getUsernamesFromSubject(sub);
+ this.parameters = parameters;
+ }
+
+ protected AdminCommandInstanceImpl(String name, String scope, Subject sub, boolean managedJob, ParameterMap parameters) {
+ this(null, name, scope, sub, managedJob, parameters);
+ }
+
+ @Override
+ public CommandProgress getCommandProgress() {
+ return commandProgress;
+ }
+
+ @Override
+ public void setCommandProgress(CommandProgress commandProgress) {
+ this.commandProgress = commandProgress;
+ commandProgress.setEventBroker(broker);
+ }
+
+ @Override
+ public AdminCommandEventBroker getEventBroker() {
+ return this.broker;
+ }
+
+ public void setEventBroker(AdminCommandEventBroker eventBroker) {
+ this.broker = eventBroker;
+ }
+
+ @Override
+ public File getJobsFile() {
+ return jobsFile;
+ }
+
+ @Override
+ public void setJobsFile(File jobsFile) {
+ this.jobsFile = jobsFile;
+ }
+
+ @Override
+ public List<String> getSubjectUsernames() {
+ return subjectUsernames;
+ }
+
+ @Override
+ public String getName() {
+ return commandName;
+ }
+
+ @Override
+ protected void setState(State state) {
+ if (state != null && state != getState()) {
+ super.setState(state);
+ getEventBroker().fireEvent(EVENT_STATE_CHANGED, this);
+ }
+ }
+
+ @Override
+ public boolean isOutboundPayloadEmpty() {
+ return payload == null || payload.size() == 0;
+ }
+
+ @Override
+ public void complete(ActionReport report, Payload.Outbound outbound) {
+ if (commandProgress != null && report != null && report.getActionExitCode() == ExitCode.SUCCESS) {
+ commandProgress.complete();
+ }
+ super.actionReport = report;
+ this.payload = outbound;
+ this.completionDate = System.currentTimeMillis();
+ if (isManagedJob) {
+ if (getState().equals(State.RUNNING_RETRYABLE) && failToRetryable) {
+ JobManagerService jobManager = Globals.getDefaultHabitat().getService(JobManagerService.class);
+ jobManager.getRetryableJobsInfo().put(id, CheckpointHelper.CheckpointFilename.createBasic(this));
+ jobManager.purgeJob(id);
+ setState(State.FAILED_RETRYABLE);
+ } else {
+ JobPersistence jobPersistenceService;
+ if (scope != null) {
+ jobPersistenceService = Globals.getDefaultHabitat().getService(JobPersistence.class,scope+"job-persistence");
+ } else {
+ jobPersistenceService = Globals.getDefaultHabitat().getService(JobPersistenceService.class);
+ }
+ State finalState = State.COMPLETED;
+ if (getState().equals(State.REVERTING)) {
+ finalState = State.REVERTED;
+ }
+ String user = null;
+ if(subjectUsernames.size() > 0){
+ user = subjectUsernames.get(0);
+ }
+ jobPersistenceService.persist(new JobInfo(id,commandName,executionDate,report.getActionExitCode().name(),user,report.getMessage(),getJobsFile(),finalState.name(),completionDate));
+ if (getState().equals(State.RUNNING_RETRYABLE) || getState().equals(State.REVERTING)) {
+ JobManagerService jobManager = Globals.getDefaultHabitat().getService(JobManagerService.class);
+ File jobFile = getJobsFile();
+ if (jobFile == null) {
+ jobFile = jobManager.getJobsFile();
+ }
+ jobManager.deleteCheckpoint(jobFile.getParentFile(), getId());
+ }
+ setState(finalState);
+ }
+ } else {
+ setState(State.COMPLETED);
+ }
+ }
+
+ @Override
+ public void revert() {
+ setState(State.REVERTING);
+ }
+
+ @Override
+ public long getCommandExecutionDate () {
+ return executionDate;
+
+ }
+
+ @Override
+ public Payload.Outbound getPayload() {
+ return payload;
+ }
+
+ @Override
+ public String getScope() {
+ return scope;
+ }
+
+ @Override
+ public long getCommandCompletionDate() {
+ return completionDate;
+ }
+
+ @Override
+ public void setFailToRetryable(boolean value) {
+ this.failToRetryable = value;
+ }
+
+ @Override
+ public ParameterMap getParameters() {
+ return parameters;
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException {
+ in.defaultReadObject();
+ this.payload = null; //Lazy loaded
+ this.broker = null; //Lazy loaded
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminConsoleConfigUpgrade.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminConsoleConfigUpgrade.java
new file mode 100644
index 0000000..fbbcd73
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminConsoleConfigUpgrade.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.*;
+import com.sun.enterprise.module.bootstrap.EarlyLogHandler;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.api.admin.config.ConfigurationUpgrade;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jvnet.hk2.annotations.Optional;
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PostConstruct;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+import org.jvnet.hk2.config.types.Property;
+
+import java.beans.PropertyVetoException;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * Adds the needed message-security-config information to domain.xml
+ * during an upgrade from a v2.X server. For more information see:
+ * https://glassfish.dev.java.net/issues/show_bug.cgi?id=13443
+ */
+@Service
+public class AdminConsoleConfigUpgrade implements ConfigurationUpgrade, PostConstruct {
+
+ private static final String AUTH_LAYER = "HttpServlet";
+ private static final String PROVIDER_TYPE = "server";
+ private static final String PROVIDER_ID = "GFConsoleAuthModule";
+ private static final String CLASS_NAME =
+ "org.glassfish.admingui.common.security.AdminConsoleAuthModule";
+ private static final String AUTH_SOURCE = "sender";
+ private static final String AUTH_URL_VAL_TEMPLATE =
+ "http://localhost:%s/management/sessions";
+ public static final String DEFAULT_ADMIN_PORT = "4848";
+ private static final String LOGIN_PAGE_PROP = "loginPage";
+ private static final String LOGIN_PAGE_VAL = "/login.jsf";
+ private static final String LOGIN_ERR_PAGE_PROP = "loginErrorPage";
+ private static final String LOGIN_ERR_PAGE_VAL = "/loginError.jsf";
+
+ @Inject
+ Configs configs;
+
+ // This will force the Grizzly upgrade code to run before
+ // AdminConsoleConfigUpgrade runs. Issue GLASSFISH-15599
+ @Inject
+ @Named("grizzlyconfigupgrade")
+ @Optional
+ ConfigurationUpgrade precondition = null;
+
+ @Override
+ public void postConstruct() {
+ Config config = configs.getConfigByName("server-config");
+ if (config != null) {
+ SecurityService s = config.getSecurityService();
+ if (s != null) {
+ try {
+ ConfigSupport.apply(new AdminConsoleConfigCode(), s);
+ } catch (TransactionFailure tf) {
+ LogRecord lr = new LogRecord(Level.SEVERE,
+ "Could not upgrade security service for admin console: " +
+ tf);
+ lr.setLoggerName(getClass().getName());
+ EarlyLogHandler.earlyMessages.add(lr);
+ }
+ }
+ }
+ }
+
+ static private class AdminConsoleConfigCode
+ implements SingleConfigCode<SecurityService> {
+
+ @Override
+ public Object run(SecurityService service)
+ throws PropertyVetoException, TransactionFailure {
+
+ /*
+ * TODO: if the element is already present, should we check it
+ * instead of just returning? If so, don't forget to enroll
+ * it in the transaction.
+ */
+ for (MessageSecurityConfig msc :
+ service.getMessageSecurityConfig()) {
+ if (AUTH_LAYER.equals(msc.getAuthLayer())) {
+ return null;
+ }
+ }
+
+ // create/add message-security-config
+ MessageSecurityConfig msConfig =
+ service.createChild(MessageSecurityConfig.class);
+ msConfig.setAuthLayer(AUTH_LAYER);
+ service.getMessageSecurityConfig().add(msConfig);
+
+ // create/add provider-config
+ ProviderConfig pConfig = msConfig.createChild(ProviderConfig.class);
+ pConfig.setProviderType(PROVIDER_TYPE);
+ pConfig.setProviderId(PROVIDER_ID);
+ pConfig.setClassName(CLASS_NAME);
+ msConfig.getProviderConfig().add(pConfig);
+
+ // create/add request-policy
+ RequestPolicy reqPol = pConfig.createChild(RequestPolicy.class);
+ reqPol.setAuthSource(AUTH_SOURCE);
+ pConfig.setRequestPolicy(reqPol);
+
+ // create/add response-policy
+ ResponsePolicy resPol = pConfig.createChild(ResponsePolicy.class);
+ pConfig.setResponsePolicy(resPol);
+
+ // get admin port property from config
+ Config parent = service.getParent(Config.class);
+ if (parent.getAdminListener() == null) {
+ LogRecord lr = new LogRecord(Level.WARNING,
+ String.format(
+ "Couldn't get admin port from config '%s'. Using default %s",
+ parent.getName(),
+ DEFAULT_ADMIN_PORT)
+ );
+ lr.setLoggerName(getClass().getName());
+ EarlyLogHandler.earlyMessages.add(lr);
+ }
+
+ // add properties
+ Property logPageProp = pConfig.createChild(Property.class);
+ logPageProp.setName(LOGIN_PAGE_PROP);
+ logPageProp.setValue(LOGIN_PAGE_VAL);
+
+ Property logErrPage = pConfig.createChild(Property.class);
+ logErrPage.setName(LOGIN_ERR_PAGE_PROP);
+ logErrPage.setValue(LOGIN_ERR_PAGE_VAL);
+
+ List<Property> props = pConfig.getProperty();
+ props.add(logPageProp);
+ props.add(logErrPage);
+
+ return null;
+ }
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminRESTConfigUpgrade.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminRESTConfigUpgrade.java
new file mode 100644
index 0000000..4af5b4a
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AdminRESTConfigUpgrade.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.Configs;
+import com.sun.enterprise.module.bootstrap.EarlyLogHandler;
+import org.glassfish.grizzly.config.dom.Http;
+import org.glassfish.grizzly.config.dom.Protocol;
+import org.glassfish.grizzly.config.dom.Protocols;
+import org.glassfish.api.admin.config.ConfigurationUpgrade;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jvnet.hk2.annotations.Optional;
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PostConstruct;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+
+import java.beans.PropertyVetoException;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * Adds the needed http.setEncodedSlashEnabled to domain.xml
+ * during an upgrade from a v2.X server. For more information see:
+ * https://glassfish.dev.java.net/issues/show_bug.cgi?id=13627
+ */
+@Service
+public class AdminRESTConfigUpgrade
+ implements ConfigurationUpgrade, PostConstruct {
+
+ @Inject
+ Configs configs;
+
+ // http://java.net/jira/browse/GLASSFISH-15576
+ // This will force the Grizzly upgrade code to run before
+ // AdminRESTConfigUpgrade runs.
+ @Inject @Named("grizzlyconfigupgrade") @Optional
+ ConfigurationUpgrade precondition = null;
+
+ @Override
+ public void postConstruct() {
+ for (Config config : configs.getConfig()) {
+ // we only want to handle configs that have an admin listener
+ try {
+ if (config.getAdminListener() == null) {
+ LogRecord lr = new LogRecord(Level.FINE, String.format(
+ "Skipping config %s. No admin listener.",
+ config.getName()));
+ lr.setLoggerName(getClass().getName());
+ EarlyLogHandler.earlyMessages.add(lr);
+ continue;
+ }
+ } catch (IllegalStateException ise) {
+ /*
+ * I've only seen the exception rather than
+ * getAdminListener returning null. This should
+ * typically happen for any config besides
+ * <server-config>, but we'll proceed if any
+ * config has an admin listener.
+ */
+ LogRecord lr = new LogRecord(Level.FINE, String.format(
+ "Skipping config %s. getAdminListener threw: %s",
+ config.getName(), ise.getLocalizedMessage()));
+ lr.setLoggerName(getClass().getName());
+ EarlyLogHandler.earlyMessages.add(lr);
+ continue;
+ }
+ Protocols ps = config.getNetworkConfig().getProtocols();
+ if (ps != null) {
+ for (Protocol p : ps.getProtocol()) {
+ Http h = p.getHttp();
+ if (h != null
+ && "__asadmin".equals(h.getDefaultVirtualServer())) {
+ try {
+ ConfigSupport.apply(new HttpConfigCode(), h);
+ } catch (TransactionFailure tf) {
+ LogRecord lr = new LogRecord(Level.SEVERE,
+ "Could not upgrade http element for admin console: "+ tf);
+ lr.setLoggerName(getClass().getName());
+ EarlyLogHandler.earlyMessages.add(lr);
+ }
+ }
+ }
+
+
+ }
+ }
+ }
+
+
+ static private class HttpConfigCode implements SingleConfigCode<Http> {
+
+ @Override
+ public Object run(Http http) throws PropertyVetoException,
+ TransactionFailure {
+
+ http.setEncodedSlashEnabled("true");
+ return null;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AppServerMBeanServerBuilder.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AppServerMBeanServerBuilder.java
new file mode 100644
index 0000000..59bf0ec
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/AppServerMBeanServerBuilder.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerBuilder;
+
+/**
+ * AppServer MBSBuilder for PE set as the value for javax.management.initial.builder
+ * in the environment. This builder extends from javax.management.MBeanServerBuilder
+ * and creates MBS with app server interceptors
+ */
+public class AppServerMBeanServerBuilder extends javax.management.MBeanServerBuilder {
+ private static final MBeanServerBuilder defaultBuilder = new MBeanServerBuilder();
+ private static MBeanServer _defaultMBeanServer = null;
+
+ public MBeanServer newMBeanServer(String defaultDomain,
+ MBeanServer outer,
+ MBeanServerDelegate delegate) {
+ MBeanServer mbeanServer;
+ synchronized (AppServerMBeanServerBuilder.class) {
+ if ( _defaultMBeanServer == null ) {
+ mbeanServer = newAppServerMBeanServer(defaultDomain, delegate);
+ _defaultMBeanServer = mbeanServer;
+ }
+ else {
+ mbeanServer = defaultBuilder.newMBeanServer(
+ defaultDomain, outer, delegate);
+ }
+ }
+ return mbeanServer;
+ }
+
+ protected MBeanServer newAppServerMBeanServer(String defaultDomain,
+ MBeanServerDelegate delegate) {
+ final DynamicInterceptor result = new DynamicInterceptor();
+ final MBeanServer jmxMBS = defaultBuilder.newMBeanServer(
+ defaultDomain, result, delegate);
+ result.setDelegateMBeanServer( jmxMBS );
+
+ return result;
+ }
+
+ public MBeanServerDelegate newMBeanServerDelegate() {
+ return defaultBuilder.newMBeanServerDelegate();
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CLIUtil.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CLIUtil.java
new file mode 100644
index 0000000..a16aa5e
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CLIUtil.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.SystemPropertyBag;
+import org.glassfish.internal.api.Target;
+import org.jvnet.hk2.config.types.Property;
+
+/**
+ *
+ * @author tjquinn
+ */
+public class CLIUtil {
+
+ static Config chooseConfig(final Target targetService,
+ Config config,
+ final String target) {
+ Config targetConfig = targetService.getConfig(target);
+ if (targetConfig != null) {
+ config = targetConfig;
+ }
+ return config;
+ }
+
+ static SystemPropertyBag chooseTarget(final Domain domain, final String target) {
+ SystemPropertyBag spb = null;
+ Property domainProp = domain.getProperty("administrative.domain.name");
+ String domainName = domainProp.getValue();
+ if ("domain".equals(target) || target.equals(domainName)) {
+ spb = domain;
+ } else {
+ spb = domain.getConfigNamed(target);
+ if (spb == null) {
+ spb = domain.getClusterNamed(target);
+ }
+ if (spb == null) {
+ spb = domain.getServerNamed(target);
+ }
+ }
+ return spb;
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CheckpointHelper.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CheckpointHelper.java
new file mode 100644
index 0000000..ce6c6f8
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CheckpointHelper.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.StringUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.inject.Inject;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+
+import org.glassfish.admin.payload.PayloadImpl;
+import org.glassfish.api.admin.Payload;
+import org.glassfish.api.admin.Payload.Inbound;
+import org.glassfish.api.admin.Payload.Outbound;
+import org.glassfish.api.admin.Payload.Part;
+
+import com.sun.enterprise.util.io.FileUtils;
+import java.io.FilenameFilter;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.api.admin.Job;
+import org.glassfish.api.admin.JobManager;
+import org.glassfish.common.util.ObjectInputOutputStreamFactory;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.security.services.api.authentication.AuthenticationService;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * This class is starting point for persistent CheckpointHelper, and currently only
+ * persists and restores AdminCommandContext with payloads in separate files.
+ *
+ * @author Andriy Zhdanov
+ *
+ */
+@Service
+public class CheckpointHelper {
+
+ public static class CheckpointFilename {
+
+ enum ExtensionType {
+ BASIC, ATTACHMENT, PAYLOAD_INBOUD, PAYLOAD_OUTBOUND;
+ }
+
+ private static final Map<ExtensionType, String> EXTENSIONS;
+ static {
+ Map<ExtensionType, String> extMap = new EnumMap<ExtensionType, String>(ExtensionType.class);
+ extMap.put(ExtensionType.BASIC, ".checkpoint");
+ extMap.put(ExtensionType.ATTACHMENT, ".checkpoint_attach");
+ extMap.put(ExtensionType.PAYLOAD_INBOUD, ".checkpoint_inb");
+ extMap.put(ExtensionType.PAYLOAD_OUTBOUND, ".checkpoint_outb");
+ EXTENSIONS = Collections.unmodifiableMap(extMap);
+ }
+
+ private final ExtensionType ext;
+ private final String jobId;
+ private String attachmentId;
+ private final File parentDir;
+
+ private String cachedFileName;
+
+ private CheckpointFilename(String jobId, File parentDir, ExtensionType ext) {
+ this.ext = ext;
+ this.jobId = jobId;
+ this.parentDir = parentDir;
+ }
+
+ private CheckpointFilename(CheckpointFilename basic, ExtensionType ext) {
+ this.ext = ext;
+ this.jobId = basic.jobId;
+ this.attachmentId = basic.attachmentId;
+ this.parentDir = basic.parentDir;
+ }
+
+ private CheckpointFilename(Job job, String attachmentId) {
+ this(job.getId(), job.getJobsFile().getParentFile(), ExtensionType.ATTACHMENT);
+ this.attachmentId = attachmentId;
+ }
+
+ public CheckpointFilename(File file) throws IOException {
+ this.parentDir = file.getParentFile();
+ String name = file.getName();
+ this.cachedFileName = name;
+ //Find extension
+ int ind = name.lastIndexOf('.');
+ if (ind <= 0) {
+ throw new IOException(strings.getLocalString("checkpointhelper.wrongfileextension", "Wrong checkpoint file extension {0}", file.getName()));
+ }
+ String extensionStr = name.substring(ind);
+ ExtensionType extension = null;
+ for (Map.Entry<ExtensionType, String> entry : EXTENSIONS.entrySet()) {
+ if (extensionStr.equals(entry.getValue())) {
+ extension = entry.getKey();
+ break;
+ }
+ }
+ if (extension == null) {
+ throw new IOException(strings.getLocalString("checkpointhelper.wrongfileextension", "Wrong checkpoint file extension {0}", file.getName()));
+ }
+ this.ext = extension;
+ //Parse id
+ name = name.substring(0, ind);
+ if (this.ext == ExtensionType.ATTACHMENT) {
+ ind = name.indexOf('-');
+ if (ind < 0) {
+ throw new IOException(strings.getLocalString("checkpointhelepr.wrongfilename", "Wrong checkpoint filename format: {0}.", file.getName()));
+ }
+ this.jobId = name.substring(0, ind);
+ this.attachmentId = name.substring(ind + 1);
+ } else {
+ this.jobId = name;
+ }
+ }
+
+ public ExtensionType getExt() {
+ return ext;
+ }
+
+ public String getJobId() {
+ return jobId;
+ }
+
+ public String getAttachmentId() {
+ return attachmentId;
+ }
+
+ public File getParentDir() {
+ return parentDir;
+ }
+
+ @Override
+ public String toString() {
+ if (cachedFileName == null) {
+ StringBuilder result = new StringBuilder();
+ result.append(jobId);
+ if (ext == ExtensionType.ATTACHMENT) {
+ result.append("-");
+ if (attachmentId == null) {
+ result.append("null");
+ } else if (!attachmentId.isEmpty()) {
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] thedigest = md.digest(attachmentId.getBytes("UTF-8"));
+ for (int i = 0; i < thedigest.length; i++) {
+ result.append(Integer.toString((thedigest[i] & 0xff) + 0x100, 16).substring(1));
+ }
+ } catch (Exception ex) {
+ result.append(attachmentId);
+ }
+ }
+ }
+ result.append(EXTENSIONS.get(ext));
+ cachedFileName = result.toString();
+ }
+ return cachedFileName;
+ }
+
+ public File getFile() {
+ return new File(parentDir, toString());
+ }
+
+ public CheckpointFilename getForPayload(boolean inbound) {
+ return new CheckpointFilename(this, inbound ? ExtensionType.PAYLOAD_INBOUD : ExtensionType.PAYLOAD_OUTBOUND);
+ }
+
+ public static CheckpointFilename createBasic(Job job) {
+ return createBasic(job.getId(), job.getJobsFile().getParentFile());
+ }
+
+ public static CheckpointFilename createBasic(String jobId, File dir) {
+ return new CheckpointFilename(jobId, dir, ExtensionType.BASIC);
+ }
+
+ public static CheckpointFilename createAttachment(Job job, String attachmentId) {
+ return new CheckpointFilename(job, attachmentId);
+ }
+
+ }
+
+ private final static LocalStringManagerImpl strings = new LocalStringManagerImpl(CheckpointHelper.class);
+
+ @Inject
+ AuthenticationService authenticationService;
+
+ @Inject
+ ServiceLocator serviceLocator;
+
+ @Inject
+ ObjectInputOutputStreamFactory factory;
+
+ public void save(JobManager.Checkpoint checkpoint) throws IOException {
+ CheckpointFilename cf = CheckpointFilename.createBasic(checkpoint.getJob());
+ ObjectOutputStream oos = null;
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(cf.getFile());
+ oos = factory.createObjectOutputStream(fos);
+ oos.writeObject(checkpoint);
+ oos.close();
+ Outbound outboundPayload = checkpoint.getContext().getOutboundPayload();
+ if (outboundPayload != null && outboundPayload.isDirty()) {
+ saveOutbound(outboundPayload, cf.getForPayload(false).getFile());
+ }
+ Inbound inboundPayload = checkpoint.getContext().getInboundPayload();
+ if (inboundPayload != null) {
+ saveInbound(inboundPayload, cf.getForPayload(true).getFile());
+ }
+ } catch (IOException e) {
+ try {oos.close();} catch (Exception ex) {
+ }
+ try {fos.close();} catch (Exception ex) {
+ }
+ File file = cf.getFile();
+ if (file.exists()) {
+ file.delete();;
+ }
+ file = cf.getForPayload(true).getFile();
+ if (file.exists()) {
+ file.delete();
+ }
+ file = cf.getForPayload(false).getFile();
+ if (file.exists()) {
+ file.delete();
+ }
+ throw e;
+ }
+ }
+
+ public void saveAttachment(Serializable data, Job job, String attachmentId) throws IOException {
+ ObjectOutputStream oos = null;
+ FileOutputStream fos = null;
+ CheckpointFilename cf = CheckpointFilename.createAttachment(job, attachmentId);
+ try {
+ fos = new FileOutputStream(cf.getFile());
+ oos = factory.createObjectOutputStream(fos);
+ oos.writeObject(data);
+ } finally {
+ try {oos.close();} catch (Exception ex) {
+ }
+ try {fos.close();} catch (Exception ex) {
+ }
+ }
+ }
+
+ public JobManager.Checkpoint load(CheckpointFilename cf, Outbound outbound) throws IOException, ClassNotFoundException {
+ FileInputStream fis = null;
+ ObjectInputStream ois = null;
+ JobManager.Checkpoint checkpoint;
+ try {
+ fis = new FileInputStream(cf.getFile());
+ ois = factory.createObjectInputStream(fis);
+ checkpoint = (JobManager.Checkpoint) ois.readObject();
+ } finally {
+ try {ois.close();} catch (Exception ex) {
+ }
+ try {fis.close();} catch (Exception ex) {
+ }
+ }
+ if (outbound != null) {
+ loadOutbound(outbound, cf.getForPayload(false).getFile());
+ checkpoint.getContext().setOutboundPayload(outbound);
+ }
+ Inbound inbound = loadInbound(cf.getForPayload(true).getFile());
+ checkpoint.getContext().setInboundPayload(inbound);
+ try {
+ String username = checkpoint.getJob().getSubjectUsernames().get(0);
+ Subject subject = authenticationService.impersonate(username, /* groups */ null, /* subject */ null, /* virtual */ false);
+ checkpoint.getContext().setSubject(subject);
+ } catch (LoginException e) {
+ throw new RuntimeException(e);
+ }
+ return checkpoint;
+ }
+
+ public <T extends Serializable> T loadAttachment(Job job, String attachmentId) throws IOException, ClassNotFoundException {
+ CheckpointFilename cf = CheckpointFilename.createAttachment(job, attachmentId);
+ File file = cf.getFile();
+ if (!file.exists()) {
+ return null;
+ }
+ ObjectInputStream ois = null;
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(cf.getFile());
+ ois = factory.createObjectInputStream(fis);
+ return (T) ois.readObject();
+ } finally {
+ try {ois.close();} catch (Exception ex) {
+ }
+ try {fis.close();} catch (Exception ex) {
+ }
+ }
+ }
+
+ public Collection<CheckpointFilename> listCheckpoints(File dir) {
+ if (dir == null || !dir.exists()) {
+ return Collections.emptyList();
+ }
+ final String extension = CheckpointFilename.EXTENSIONS.get(CheckpointFilename.ExtensionType.BASIC);
+ File[] checkpointFiles = dir.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(extension);
+ }
+ });
+ if (checkpointFiles != null) {
+ Collection<CheckpointFilename> result = new ArrayList<CheckpointFilename>(checkpointFiles.length);
+ for (File checkpointFile : checkpointFiles) {
+ try {
+ result.add(new CheckpointFilename(checkpointFile));
+ } catch (IOException ex) {
+ }
+ }
+ return result;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+/*
+ private void writeHeader(OutputStream os, Job job) throws IOException {
+ writeHeader(os, StringUtils.nvl(job.getScope()) + job.getName());
+ }
+
+ private void writeHeader(OutputStream os, String headerStr) throws IOException {
+ byte[] headerB = headerStr.getBytes("UTF-8");
+ int len = headerB.length;
+ while (len >= 255) {
+ os.write(255);
+ len -= 255;
+ }
+ os.write(len);
+ os.write(headerB);
+ }
+
+ private String readHeader(InputStream is) throws IOException {
+ int length = 0;
+ int r;
+ while ((r = is.read()) == 255) {
+ length += 255;
+ }
+ if (r < 0) {
+ throw new IOException(strings.getLocalString("checkpointhelper.wrongheader", "Can not load checkpoint. Wrong header."));
+ }
+ length += r;
+ byte[] headerB = new byte[length];
+ int readLen = is.read(headerB);
+ if (readLen < length) {
+ throw new IOException(strings.getLocalString("checkpointhelper.wrongheader", "Can not load checkpoint. Wrong header."));
+ }
+ return new String(headerB, "UTF-8");
+ }
+
+ private ObjectInputStream getObjectInputStream(InputStream is, String header) throws IOException {
+ if (!StringUtils.ok(header)) {
+ return new ObjectInputStream(is);
+ }
+ AdminCommand command = serviceLocator.getService(AdminCommand.class, header);
+ if (command == null) {
+ throw new IOException(strings.getLocalString("checkpointhelper.cannotlocatecommand", "Can not load checkpoint. Can not locate command {0}.", header));
+ }
+ List<ClassLoader> cls = new ArrayList<ClassLoader>(10);
+ cls.add(command.getClass().getClassLoader());
+ cls.add(this.getClass().getClassLoader());
+ cls.add(ClassLoader.getSystemClassLoader());
+ cls.addAll(getJobCreators());
+ return new ObjectInputStreamForClassloader(is, cls);
+ }
+ private List<ClassLoader> getJobCreators() {
+ List<JobCreator> jcs = serviceLocator.getAllServices(JobCreator.class);
+ if (jcs == null) {
+ return Collections.EMPTY_LIST;
+ }
+ List<ClassLoader> result = new ArrayList<ClassLoader>(jcs.size());
+ for (JobCreator jc : jcs) {
+ result.add(jc.getClass().getClassLoader());
+ }
+ return result;
+ }
+*/
+
+ private void saveOutbound(Payload.Outbound outbound, File outboundFile) throws IOException {
+ FileOutputStream os = new FileOutputStream(outboundFile);
+ // Outbound saves text/plain with one part as text with no any details, force zip
+ writePartsTo(outbound.parts(), os);
+ outbound.resetDirty();
+ }
+
+ private void loadOutbound(Outbound outbound, File outboundFile) throws IOException {
+ if (outbound == null || !outboundFile.exists()) {
+ return;
+ }
+ Inbound outboundSource = loadInbound(outboundFile);
+ Iterator<Part> parts = outboundSource.parts();
+ File topDir = createTempDir("checkpoint", "");
+ topDir.deleteOnExit();
+ while (parts.hasNext()) {
+ Part part = parts.next();
+ File sourceFile = File.createTempFile("source", "", topDir);
+ FileUtils.copy(part.getInputStream(), new FileOutputStream(sourceFile), Long.MAX_VALUE);
+ outbound.addPart(part.getContentType(), part.getName(), part.getProperties(), new FileInputStream(sourceFile));
+ }
+ outbound.resetDirty();
+ }
+
+ private void saveInbound(Payload.Inbound inbound, File inboundFile) throws IOException {
+ if (!inboundFile.exists()) { // not saved yet
+ FileOutputStream os = new FileOutputStream(inboundFile);
+ writePartsTo(inbound.parts(), os);
+ }
+ }
+
+ private Inbound loadInbound(File inboundFile) throws IOException {
+ if (inboundFile == null || !inboundFile.exists()) {
+ return null;
+ }
+ FileInputStream is = new FileInputStream(inboundFile);
+ Inbound inboundSource = PayloadImpl.Inbound.newInstance("application/zip", is);
+ return inboundSource;
+ }
+
+ // ZipPayloadImpl
+
+ private void writePartsTo(Iterator<Part> parts, OutputStream os) throws IOException {
+ ZipOutputStream zos = new ZipOutputStream(os);
+ while (parts.hasNext()) {
+ Part part = parts.next();
+ prepareEntry(part, zos);
+ part.copy(zos);
+ zos.closeEntry();
+ }
+ zos.close();
+ }
+
+ private void prepareEntry(final Payload.Part part, final ZipOutputStream zos) throws IOException {
+ ZipEntry entry = new ZipEntry(part.getName());
+ entry.setExtra(getExtraBytes(part));
+ zos.putNextEntry(entry);
+ }
+
+ private byte[] getExtraBytes(Part part) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ Properties props = part.getProperties();
+ Properties fullProps = new Properties();
+ if (props != null) {
+ fullProps.putAll(props);
+ }
+ fullProps.setProperty(CONTENT_TYPE_NAME, part.getContentType());
+ try {
+ fullProps.store(baos, null);
+ return baos.toByteArray();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private File createTempDir(final String prefix, final String suffix) throws IOException {
+ File temp = File.createTempFile(prefix, suffix);
+ if ( ! temp.delete()) {
+ throw new IOException("Cannot delete temp file " + temp.getAbsolutePath());
+ }
+ if ( ! temp.mkdirs()) {
+ throw new IOException("Cannot create temp directory" + temp.getAbsolutePath());
+ }
+ return temp;
+ }
+
+ private static final String CONTENT_TYPE_NAME = "Content-Type";
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CommandNotFoundException.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CommandNotFoundException.java
new file mode 100644
index 0000000..2546fc3
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CommandNotFoundException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+/**
+ * HK2 has an Injection Manager. CommandRunner makes an instance of this Injection
+ * Manager and overrides/overrides some methods. Now we throw an Exception out. If it
+ * is a ComponentException and if the field is optional -- HK2 swallows the
+ * Exception.
+ * So, instead, we throw this RuntimeException and HK2 will propagate it back as
+ * a wrapped Exception.
+ * Then we look at the cause and pull out the real error message.
+ * @author bnevins
+ */
+class CommandNotFoundException extends RuntimeException{
+
+ CommandNotFoundException(String msg) {
+ super(msg);
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CommandRunnerImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CommandRunnerImpl.java
new file mode 100644
index 0000000..6b6a584
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CommandRunnerImpl.java
@@ -0,0 +1,2101 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.admin.event.AdminCommandEventBrokerImpl;
+import com.sun.enterprise.admin.util.*;
+import com.sun.enterprise.config.serverbeans.Cluster;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.universal.collections.ManifestUtils;
+import com.sun.enterprise.universal.glassfish.AdminCommandResponse;
+import com.sun.enterprise.util.AnnotationUtil;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.StringUtils;
+import com.sun.enterprise.v3.common.XMLContentActionReporter;
+import java.io.*;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.locks.Lock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Scope;
+import javax.inject.Singleton;
+import javax.security.auth.Subject;
+import javax.validation.*;
+import org.glassfish.admin.payload.PayloadFilesManager;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.admin.AdminCommandEventBroker.AdminCommandListener;
+import org.glassfish.api.admin.Payload;
+import org.glassfish.api.admin.ProcessEnvironment;
+import org.glassfish.api.admin.SupplementalCommandExecutor.SupplementalCommand;
+import org.glassfish.api.logging.LogHelper;
+import org.glassfish.common.util.admin.CommandModelImpl;
+import org.glassfish.common.util.admin.ManPageFinder;
+import org.glassfish.common.util.admin.MapInjectionResolver;
+import org.glassfish.common.util.admin.UnacceptableValueException;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.GenericCrudCommand;
+import org.glassfish.config.support.TargetType;
+import org.glassfish.hk2.api.MultiException;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.api.*;
+import org.glassfish.internal.deployment.DeploymentTargetResolver;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.component.*;
+import org.jvnet.hk2.config.InjectionManager;
+import org.jvnet.hk2.config.InjectionResolver;
+import org.jvnet.hk2.config.MessageInterpolatorImpl;
+import org.jvnet.hk2.config.UnsatisfiedDependencyException;
+
+/**
+ * Encapsulates the logic needed to execute a server-side command (for example,
+ * a descendant of AdminCommand) including injection of argument values into the
+ * command.
+ *
+ * @author dochez
+ * @author tjquinn
+ * @author Bill Shannon
+ */
+@Service
+public class CommandRunnerImpl implements CommandRunner {
+
+ private static final Logger logger = KernelLoggerInfo.getLogger();
+ // This is used only for backword compatibility with old behavior
+ private static final String OLD_PASSWORD_PARAM_PREFIX = "AS_ADMIN_";
+
+ private static final InjectionManager injectionMgr = new InjectionManager();
+ @Inject
+ private ServiceLocator habitat;
+ @Inject
+ private ServerContext sc;
+ @Inject
+ private Domain domain;
+ @Inject
+ private ServerEnvironment serverEnv;
+ @Inject
+ private ProcessEnvironment processEnv;
+ @Inject
+ private InstanceStateService state;
+ @Inject
+ private AdminCommandLock adminLock;
+ @Inject @Named("SupplementalCommandExecutorImpl")
+ SupplementalCommandExecutor supplementalExecutor;
+
+
+ //private final Map<Class<? extends AdminCommand>, String> commandModelEtagMap = new WeakHashMap<Class<? extends AdminCommand>, String>();
+ private final Map<NameCommandClassPair, String> commandModelEtagMap = new IdentityHashMap<NameCommandClassPair, String>();
+
+ @Inject
+ private CommandSecurityChecker commandSecurityChecker;
+
+ private static final LocalStringManagerImpl adminStrings =
+ new LocalStringManagerImpl(CommandRunnerImpl.class);
+ private static volatile Validator beanValidator = null;
+
+ /**
+ * Returns an initialized ActionReport instance for the passed type or
+ * null if it cannot be found.
+ *
+ * @param name action report type name
+ * @return uninitialized action report or null
+ */
+ @Override
+ public ActionReport getActionReport(String name) {
+ return habitat.getService(ActionReport.class, name);
+ }
+
+ /**
+ * Returns the command model for a command name.
+ *
+ * @param commandName command name
+ * @param logger logger to log any error messages
+ * @return model for this command (list of parameters,etc...),
+ * or null if command is not found
+ */
+ @Override
+ public CommandModel getModel(String commandName, Logger logger) {
+ return getModel(null, commandName, logger);
+ }
+
+ /**
+ * Returns the command model for a command name.
+ *
+ * @param commandName command name
+ * @param logger logger to log any error messages
+ * @return model for this command (list of parameters,etc...),
+ * or null if command is not found
+ */
+ @Override
+ public CommandModel getModel(String scope, String commandName, Logger logger) {
+ AdminCommand command;
+ try {
+ String commandServiceName = (scope != null) ? scope + commandName : commandName;
+ command = habitat.getService(AdminCommand.class, commandServiceName);
+ } catch (MultiException e) {
+ LogHelper.log(logger, Level.SEVERE, KernelLoggerInfo.cantInstantiateCommand,
+ e, commandName);
+ return null;
+ }
+ return command == null ? null : getModel(command);
+ }
+
+ @Override
+ public boolean validateCommandModelETag(AdminCommand command, String eTag) {
+ if (command == null) {
+ return true; //Everithing is ok for unexisting command
+ }
+ if (eTag == null || eTag.isEmpty()) {
+ return false;
+ }
+ CommandModel model = getModel(command);
+ return validateCommandModelETag(model, eTag);
+ }
+
+ @Override
+ public boolean validateCommandModelETag(CommandModel model, String eTag) {
+ if (model == null) {
+ return true; //Unexisting model => it is ok (but weard in fact)
+ }
+ if (eTag == null || eTag.isEmpty()) {
+ return false;
+ }
+ String actualETag = CachedCommandModel.computeETag(model);
+ return eTag.equals(actualETag);
+ }
+
+ /**
+ * Obtain and return the command implementation defined by
+ * the passed commandName for the null scope.
+ *
+ * @param commandName command name as typed by users
+ * @param report report used to communicate command status back to the user
+ * @param logger logger to log
+ * @return command registered under commandName or null if not found
+ */
+ @Override
+ public AdminCommand getCommand(String commandName,
+ ActionReport report, Logger logger) {
+ return getCommand(null, commandName, report, logger);
+ }
+
+ private static Class<? extends Annotation> getScope(Class<?> onMe) {
+ for (Annotation anno : onMe.getAnnotations()) {
+ if (anno.annotationType().isAnnotationPresent(Scope.class)) {
+ return anno.annotationType();
+ }
+
+ }
+
+ return null;
+ }
+
+ /**
+ * Obtain and return the command implementation defined by
+ * the passed commandName.
+ *
+ * @param commandName command name as typed by users
+ * @param report report used to communicate command status back to the user
+ * @param logger logger to log
+ * @return command registered under commandName or null if not found
+ */
+ @Override
+ public AdminCommand getCommand(String scope, String commandName,
+ ActionReport report, Logger logger) {
+
+ AdminCommand command = null;
+ String commandServiceName = (scope != null) ? scope + commandName : commandName;
+
+ try {
+ command = habitat.getService(AdminCommand.class, commandServiceName);
+ } catch (MultiException e) {
+ report.setFailureCause(e);
+ }
+ if (command == null) {
+ String msg;
+
+ if (!ok(commandName)) {
+ msg = adminStrings.getLocalString("adapter.command.nocommand",
+ "No command was specified.");
+ } else {
+ // this means either a non-existent command or
+ // an ill-formed command
+ if (habitat.getServiceHandle(AdminCommand.class, commandServiceName)
+ == null) // somehow it's in habitat
+ {
+ msg = adminStrings.getLocalString("adapter.command.notfound", "Command {0} not found", commandName);
+ } else {
+ msg = adminStrings.getLocalString("adapter.command.notcreated",
+ "Implementation for the command {0} exists in "
+ + "the system, but it has some errors, "
+ + "check server.log for details", commandName);
+ }
+ }
+ report.setMessage(msg);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ KernelLoggerInfo.getLogger().fine(msg);
+ return null;
+ }
+
+ Class<? extends Annotation> myScope = getScope(command.getClass());
+ if (myScope == null) {
+ String msg = adminStrings.getLocalString("adapter.command.noscope",
+ "Implementation for the command {0} exists in the "
+ + "system,\nbut it has no @Scoped annotation", commandName);
+ report.setMessage(msg);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ KernelLoggerInfo.getLogger().fine(msg);
+ command = null;
+ } else if (Singleton.class.equals(myScope)) {
+ // check that there are no parameters for this command
+ CommandModel model = getModel(command);
+ if (model.getParameters().size() > 0) {
+ String msg =
+ adminStrings.getLocalString("adapter.command.hasparams",
+ "Implementation for the command {0} exists in the "
+ + "system,\nbut it's a singleton that also has "
+ + "parameters", commandName);
+ report.setMessage(msg);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ KernelLoggerInfo.getLogger().fine(msg);
+ command = null;
+ }
+ }
+
+ return command;
+ }
+
+ @Override
+ public CommandInvocation getCommandInvocation(String name, ActionReport report, Subject subject) {
+ return getCommandInvocation(name,report,subject,false);
+ }
+
+ @Override
+ public CommandInvocation getCommandInvocation(String scope, String name, ActionReport report, Subject subject) {
+ return getCommandInvocation(scope,name,report,subject,false);
+ }
+
+ /**
+ * Obtain a new command invocation object for the null scope.
+ * Command invocations can be configured and used
+ * to trigger a command execution.
+ *
+ * @param name name of the requested command to invoke
+ * @param report where to place the status of the command execution
+ * @param subject the Subject under which to execute the command
+ * @return a new command invocation for that command name
+ */
+ @Override
+ public CommandInvocation getCommandInvocation(String name,
+ ActionReport report, Subject subject,boolean isNotify) {
+ return getCommandInvocation(null, name, report, subject,false);
+ }
+
+ /**
+ * Obtain a new command invocation object.
+ * Command invocations can be configured and used
+ * to trigger a command execution.
+ *
+ * @param scope the scope (or name space) for the command
+ * @param name name of the requested command to invoke
+ * @param report where to place the status of the command execution
+ * @param subject the Subject under which to execute the command
+ * @param isNotify Should notification be enabled
+ * @return a new command invocation for that command name
+ */
+ @Override
+ public CommandInvocation getCommandInvocation(String scope, String name,
+ ActionReport report, Subject subject, boolean isNotify) {
+ return new ExecutionContext(scope, name, report, subject, isNotify);
+ }
+
+ public static boolean injectParameters(final CommandModel model, final Object injectionTarget,
+ final InjectionResolver<Param> injector,
+ final ActionReport report) {
+
+ if (injectionTarget instanceof GenericCrudCommand) {
+ GenericCrudCommand c = GenericCrudCommand.class.cast(injectionTarget);
+ c.setInjectionResolver(injector);
+ }
+
+ // inject
+ try {
+ injectionMgr.inject(injectionTarget, injector);
+ } catch (UnsatisfiedDependencyException e) {
+ Param param = e.getAnnotation(Param.class);
+ CommandModel.ParamModel paramModel = null;
+ for (CommandModel.ParamModel pModel : model.getParameters()) {
+ if (pModel.getParam().equals(param)) {
+ paramModel = pModel;
+ break;
+ }
+ }
+ String errorMsg;
+ final String usage = getUsageText(model);
+ if (paramModel != null) {
+ String paramName = paramModel.getName();
+ String paramDesc = paramModel.getLocalizedDescription();
+
+ if (param.primary()) {
+ errorMsg = adminStrings.getLocalString("commandrunner.operand.required",
+ "Operand required.");
+ } else if (param.password()) {
+ errorMsg = adminStrings.getLocalString("adapter.param.missing.passwordfile",
+ "{0} command requires the passwordfile "
+ + "parameter containing {1} entry.",
+ model.getCommandName(), paramName);
+ } else if (paramDesc != null) {
+ errorMsg = adminStrings.getLocalString("admin.param.missing",
+ "{0} command requires the {1} parameter ({2})",
+ model.getCommandName(), paramName, paramDesc);
+
+ } else {
+ errorMsg = adminStrings.getLocalString("admin.param.missing.nodesc",
+ "{0} command requires the {1} parameter",
+ model.getCommandName(), paramName);
+ }
+ } else {
+ errorMsg = adminStrings.getLocalString("admin.param.missing.nofound",
+ "Cannot find {1} in {0} command model, file a bug",
+ model.getCommandName(), e.getUnsatisfiedName());
+ }
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(errorMsg);
+ report.setFailureCause(e);
+ ActionReport.MessagePart childPart =
+ report.getTopMessagePart().addChild();
+ childPart.setMessage(usage);
+ return false;
+ }
+ catch (MultiException e) {
+ // If the cause is UnacceptableValueException -- we want the message
+ // from it. It is wrapped with a less useful Exception.
+
+ Exception exception = null;
+ for (Throwable th : e.getErrors()) {
+ Throwable cause = th;
+ while (cause != null) {
+ if ((cause instanceof UnacceptableValueException) ||
+ (cause instanceof IllegalArgumentException)) {
+ exception = (Exception) th;
+ break;
+ }
+
+ cause = cause.getCause();
+ }
+ }
+
+ if (exception == null) {
+ // Not an UnacceptableValueException or IllegalArgumentException
+ exception = e;
+ }
+
+ logger.log(Level.SEVERE, KernelLoggerInfo.invocationException, exception);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(exception.getMessage());
+ report.setFailureCause(exception);
+ ActionReport.MessagePart childPart =
+ report.getTopMessagePart().addChild();
+ childPart.setMessage(getUsageText(model));
+ return false;
+ }
+
+ checkAgainstBeanConstraints(injectionTarget, model.getCommandName());
+ return true;
+ }
+
+ private static synchronized void initBeanValidator() {
+ if (beanValidator != null) {
+ return;
+ }
+ ClassLoader cl = System.getSecurityManager() == null ?
+ Thread.currentThread().getContextClassLoader():
+ AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ @Override
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+ try {
+ Thread.currentThread().setContextClassLoader(org.hibernate.validator.HibernateValidator.class.getClassLoader());
+ ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
+ ValidatorContext validatorContext = validatorFactory.usingContext();
+ validatorContext.messageInterpolator(new MessageInterpolatorImpl());
+ beanValidator = validatorContext.getValidator();
+ } finally {
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+ }
+
+ private static void checkAgainstBeanConstraints(Object component, String cname) {
+ initBeanValidator();
+
+ Set<ConstraintViolation<Object>> constraintViolations = beanValidator.validate(component);
+ if (constraintViolations == null || constraintViolations.isEmpty()) {
+ return;
+ }
+ StringBuilder msg = new StringBuilder(adminStrings.getLocalString("commandrunner.unacceptableBV",
+ "Parameters for command {0} violate the following constraints: ",
+ cname));
+ boolean addc = false;
+ String violationMsg = adminStrings.getLocalString("commandrunner.unacceptableBV.reason",
+ "on parameter [ {1} ] violation reason [ {0} ]");
+ for (ConstraintViolation cv : constraintViolations) {
+ if (addc) {
+ msg.append(", ");
+ }
+ msg.append(MessageFormat.format(violationMsg, cv.getMessage(), cv.getPropertyPath()));
+ addc = true;
+ }
+ throw new UnacceptableValueException(msg.toString());
+ }
+
+ /**
+ * Executes the provided command object.
+ *
+ * @param model model of the command (used for logging and reporting)
+ * @param command the command service to execute
+ * @param context the AdminCommandcontext that has the payload and report
+ */
+ private ActionReport doCommand(
+ final CommandModel model,
+ final AdminCommand command,
+ final AdminCommandContext context,
+ final CommandRunnerProgressHelper progressHelper) {
+
+ ActionReport report = context.getActionReport();
+ report.setActionDescription(model.getCommandName() + " AdminCommand");
+
+ // We need to set context CL to common CL before executing
+ // the command. See issue #5596
+ final Thread thread = Thread.currentThread();
+ final ClassLoader origCL = thread.getContextClassLoader();
+ final ClassLoader ccl = sc.getCommonClassLoader();
+
+ AdminCommand wrappedCommand = new WrappedAdminCommand(command) {
+ @Override
+ public void execute(final AdminCommandContext context) {
+ try {
+ if (origCL != ccl) {
+ thread.setContextClassLoader(ccl);
+ }
+ /*
+ * Execute the command in the security context of the
+ * previously-authenticated subject.
+ */
+ Subject.doAs(context.getSubject(),
+ new PrivilegedAction<Void> () {
+
+ @Override
+ public Void run() {
+ command.execute(context);
+ return null;
+ }
+
+ });
+ } finally {
+ if (origCL != ccl) {
+ thread.setContextClassLoader(origCL);
+ }
+ }
+ }
+ };
+
+ // look for other wrappers using CommandAspect annotation
+ final AdminCommand otherWrappedCommand = CommandSupport.createWrappers(habitat, model, wrappedCommand, report);
+
+ try {
+ Subject.doAs(context.getSubject(),
+ new PrivilegedAction<Void> () {
+
+ @Override
+ public Void run() {
+ try {
+ if (origCL != ccl) {
+ thread.setContextClassLoader(ccl);
+ }
+ otherWrappedCommand.execute(progressHelper.wrapContext4MainCommand(context));
+ return null;
+ } finally {
+ if (origCL != ccl) {
+ thread.setContextClassLoader(origCL);
+ }
+ }
+ }
+
+ });
+
+ } catch (Throwable e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.invocationException, e);
+ report.setMessage(e.toString());
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ }
+
+ return context.getActionReport();
+ }
+
+ /**
+ * Get the usage-text of the command.
+ * Check if <command-name>.usagetext is defined in LocalString.properties.
+ * If defined, then use the usagetext from LocalString.properties else
+ * generate the usagetext from Param annotations in the command class.
+ *
+ * @param model command model
+ * @return usagetext
+ */
+ static String getUsageText(CommandModel model) {
+ StringBuilder usageText = new StringBuilder();
+
+ String usage;
+ if (ok(usage = model.getUsageText())) {
+ usageText.append(
+ adminStrings.getLocalString("adapter.usage", "Usage: "));
+ usageText.append(usage);
+ return usageText.toString();
+ } else {
+ return generateUsageText(model);
+ }
+ }
+
+ /**
+ * Generate the usage-text from the annotated Param in the command class.
+ *
+ * @param model command model
+ * @return generated usagetext
+ */
+ private static String generateUsageText(CommandModel model) {
+ StringBuffer usageText = new StringBuffer();
+ usageText.append(
+ adminStrings.getLocalString("adapter.usage", "Usage: "));
+ usageText.append(model.getCommandName());
+ usageText.append(" ");
+ StringBuffer operand = new StringBuffer();
+ for (CommandModel.ParamModel pModel : model.getParameters()) {
+ final Param param = pModel.getParam();
+ final String paramName =
+ pModel.getName().toLowerCase(Locale.ENGLISH);
+ // skip "hidden" options
+ if (paramName.startsWith("_")) {
+ continue;
+ }
+ // do not want to display password as an option
+ if (param.password()) {
+ continue;
+ }
+ // do not want to display obsolete options
+ if (param.obsolete()) {
+ continue;
+ }
+ final boolean optional = param.optional();
+ final Class<?> ftype = pModel.getType();
+ Object fvalue = null;
+ String fvalueString = null;
+ try {
+ fvalue = param.defaultValue();
+ if (fvalue != null) {
+ fvalueString = fvalue.toString();
+ }
+ } catch (Exception e) {
+ // just leave it as null...
+ }
+ // this is a param.
+ if (param.primary()) {
+ if (optional) {
+ operand.append("[").append(paramName).append("] ");
+ } else {
+ operand.append(paramName).append(" ");
+ }
+ continue;
+ }
+
+ if (optional) {
+ usageText.append("[");
+ }
+
+ usageText.append("--").append(paramName);
+ if (ok(param.defaultValue())) {
+ usageText.append("=").append(param.defaultValue());
+ } else if (ftype.isAssignableFrom(String.class)) {
+ // check if there is a default value assigned
+ if (ok(fvalueString)) {
+ usageText.append("=").append(fvalueString);
+ } else {
+ usageText.append("=").append(paramName);
+ }
+ } else if (ftype.isAssignableFrom(Boolean.class)) {
+ // note: There is no defaultValue for this param. It might
+ // hava value -- but we don't care -- it isn't an official
+ // default value.
+ usageText.append("=").append("true|false");
+ } else {
+ usageText.append("=").append(paramName);
+ }
+
+ if (optional) {
+ usageText.append("] ");
+ } else {
+ usageText.append(" ");
+ }
+ }
+ usageText.append(operand);
+ return usageText.toString();
+ }
+
+ @Override
+ public BufferedReader getHelp(CommandModel model) throws CommandNotFoundException {
+ BufferedReader manPage = getManPage(model.getCommandName(), model);
+ if (manPage != null) {
+ return manPage;
+ } else {
+ StringBuilder hlp = new StringBuilder(256);
+ StringBuilder part = new StringBuilder(64);
+ hlp.append("NAME").append(ManifestUtils.EOL);
+ part.append(model.getCommandName());
+ String description = model.getLocalizedDescription();
+ if (ok(description)) {
+ part.append(" - ").append(model.getLocalizedDescription());
+ }
+ hlp.append(formatGeneratedManPagePart(part.toString(), 5, 65)).append(ManifestUtils.EOL);
+ //Usage
+ hlp.append(ManifestUtils.EOL).append("SYNOPSIS").append(ManifestUtils.EOL);
+ hlp.append(formatGeneratedManPagePart(getUsageText(model), 5, 65));
+ //Options
+ hlp.append(ManifestUtils.EOL).append(ManifestUtils.EOL);
+ hlp.append("OPTIONS").append(ManifestUtils.EOL);
+ CommandModel.ParamModel operand = null;
+ for (CommandModel.ParamModel paramModel : model.getParameters()) {
+ Param param = paramModel.getParam();
+ if (param == null || paramModel.getName().startsWith("_") ||
+ param.password() || param.obsolete()) {
+ continue;
+ }
+ if (param.primary()) {
+ operand = paramModel;
+ continue;
+ }
+ hlp.append(" --").append(paramModel.getName().toLowerCase(Locale.ENGLISH));
+ hlp.append(ManifestUtils.EOL);
+ if (ok(param.shortName())) {
+ hlp.append(" -").append(param.shortName().toLowerCase(Locale.ENGLISH));
+ hlp.append(ManifestUtils.EOL);
+ }
+ String descr = paramModel.getLocalizedDescription();
+ if (ok(descr)) {
+ hlp.append(formatGeneratedManPagePart(descr, 9, 65));
+ }
+ hlp.append(ManifestUtils.EOL);
+ }
+ //Operand
+ if (operand != null) {
+ hlp.append("OPERANDS").append(ManifestUtils.EOL);
+ hlp.append(" ").append(operand.getName().toLowerCase(Locale.ENGLISH));
+ hlp.append(ManifestUtils.EOL);
+ String descr = operand.getLocalizedDescription();
+ if (ok(descr)) {
+ hlp.append(formatGeneratedManPagePart(descr, 9, 65));
+ }
+ }
+ return new BufferedReader(new StringReader(hlp.toString()));
+ }
+ }
+
+ private String formatGeneratedManPagePart(String part, int prefix, int lineLength) {
+ if (part == null) {
+ return null;
+ }
+ if (prefix < 0) {
+ prefix = 0;
+ }
+ //Prepare prefix
+ StringBuilder sb = new StringBuilder(prefix);
+ for (int i = 0; i < prefix; i++) {
+ sb.append(' ');
+ }
+ String prfx = sb.toString();
+ StringBuilder result = new StringBuilder(part.length() + prefix + 16);
+ boolean newLine = true;
+ boolean lastWasCR = false;
+ int counter = 0;
+ for (int i = 0; i < part.length(); i++) {
+ boolean addPrefix = newLine;
+ char ch = part.charAt(i);
+ switch (ch) {
+ case '\n':
+ if (!lastWasCR) {
+ newLine = true;
+ } else {
+ lastWasCR = false;
+ }
+ counter = 0;
+ break;
+ case '\r':
+ newLine = true;
+ lastWasCR = true;
+ counter = 0;
+ break;
+ default:
+ newLine = false;
+ lastWasCR = false;
+ counter++;
+ }
+ if (addPrefix && !newLine) {
+ result.append(prfx);
+ counter += prefix;
+ }
+ result.append(ch);
+ if (lineLength > 0 && counter >= lineLength && !newLine) {
+ newLine = true;
+ result.append(ManifestUtils.EOL);
+ counter = 0;
+ }
+ }
+ return result.toString();
+ }
+
+ public void getHelp(AdminCommand command, ActionReport report) {
+
+ CommandModel model = getModel(command);
+ report.setActionDescription(model.getCommandName() + " help");
+
+ // XXX - this is a hack for now. if the request mapped to an
+ // XMLContentActionReporter, that means we want the command metadata.
+ if (report instanceof XMLContentActionReporter) {
+ getMetadata(command, model, report);
+ } else {
+ report.setMessage(model.getCommandName() + " - "
+ + model.getLocalizedDescription());
+ report.getTopMessagePart().addProperty("SYNOPSIS",
+ encodeManPage(new BufferedReader(new StringReader(
+ getUsageText(model)))));
+ for (CommandModel.ParamModel param : model.getParameters()) {
+ addParamUsage(report, param);
+ }
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+ }
+
+ /**
+ * Return the metadata for the command. We translate the parameter
+ * and operand information to parts and properties of the ActionReport,
+ * which will be translated to XML elements and attributes by the
+ * XMLContentActionReporter.
+ *
+ * @param command the command
+ * @param model the CommandModel describing the command
+ * @param report the (assumed to be) XMLContentActionReporter
+ */
+ private void getMetadata(AdminCommand command, CommandModel model,
+ ActionReport report) {
+ ActionReport.MessagePart top = report.getTopMessagePart();
+ ActionReport.MessagePart cmd = top.addChild();
+ // <command name="name">
+ cmd.setChildrenType("command");
+ cmd.addProperty("name", model.getCommandName());
+ if (model.unknownOptionsAreOperands()) {
+ cmd.addProperty("unknown-options-are-operands", "true");
+ }
+ String usage = model.getUsageText();
+ if (ok(usage)) {
+ cmd.addProperty("usage", usage);
+ }
+ CommandModel.ParamModel primary = null;
+ // for each parameter add
+ // <option name="name" type="type" short="s" default="default"
+ // acceptable-values="list"/>
+ for (CommandModel.ParamModel p : model.getParameters()) {
+ Param param = p.getParam();
+ if (param.primary()) {
+ primary = p;
+ continue;
+ }
+ ActionReport.MessagePart ppart = cmd.addChild();
+ ppart.setChildrenType("option");
+ ppart.addProperty("name", p.getName());
+ ppart.addProperty("type", typeOf(p));
+ ppart.addProperty("optional", Boolean.toString(param.optional()));
+ if (param.obsolete()) // don't include it if it's false
+ {
+ ppart.addProperty("obsolete", "true");
+ }
+ String paramDesc = p.getLocalizedDescription();
+ if (ok(paramDesc)) {
+ ppart.addProperty("description", paramDesc);
+ }
+ if (ok(param.shortName())) {
+ ppart.addProperty("short", param.shortName());
+ }
+ if (ok(param.defaultValue())) {
+ ppart.addProperty("default", param.defaultValue());
+ }
+ if (ok(param.acceptableValues())) {
+ ppart.addProperty("acceptable-values", param.acceptableValues());
+ }
+ if (ok(param.alias())) {
+ ppart.addProperty("alias", param.alias());
+ }
+ }
+
+ // are operands allowed?
+ if (primary != null) {
+ // for the operand(s), add
+ // <operand type="type" min="0/1" max="1"/>
+ ActionReport.MessagePart primpart = cmd.addChild();
+ primpart.setChildrenType("operand");
+ primpart.addProperty("name", primary.getName());
+ primpart.addProperty("type", typeOf(primary));
+ primpart.addProperty("min",
+ primary.getParam().optional() ? "0" : "1");
+ primpart.addProperty("max", primary.getParam().multiple()
+ ? "unlimited" : "1");
+ String desc = primary.getLocalizedDescription();
+ if (ok(desc)) {
+ primpart.addProperty("description", desc);
+ }
+ }
+ }
+
+ /**
+ * Map a Java type to one of the types supported by the asadmin client.
+ * Currently supported types are BOOLEAN, FILE, PROPERTIES, PASSWORD, and
+ * STRING. (All of which should be defined constants on some class.)
+ *
+ * @param p the Java type
+ * @return the string representation of the asadmin type
+ */
+ private static String typeOf(CommandModel.ParamModel p) {
+ Class t = p.getType();
+ if (t == Boolean.class || t == boolean.class) {
+ return "BOOLEAN";
+ } else if (t == File.class || t == File[].class) {
+ return "FILE";
+ } else if (t == Properties.class) { // XXX - allow subclass?
+ return "PROPERTIES";
+ } else if (p.getParam().password()) {
+ return "PASSWORD";
+ } else {
+ return "STRING";
+ }
+ }
+
+ /**
+ * Return an InputStream for the man page for the named command.
+ */
+ public static BufferedReader getManPage(String commandName,
+ CommandModel model) {
+ Class clazz = model.getCommandClass();
+ if (clazz == null) {
+ return null;
+ }
+ return ManPageFinder.getCommandManPage(commandName, clazz.getName(),
+ Locale.getDefault(), clazz.getClassLoader(), logger);
+ }
+
+ private void addParamUsage(
+ ActionReport report,
+ CommandModel.ParamModel model) {
+ Param param = model.getParam();
+ if (param != null) {
+ // this is a param.
+ String paramName = model.getName().toLowerCase(Locale.ENGLISH);
+ // skip "hidden" options
+ if (paramName.startsWith("_")) {
+ return;
+ }
+ // do not want to display password in the usage
+ if (param.password()) {
+ return;
+ }
+ // do not want to display obsolete options
+ if (param.obsolete()) {
+ return;
+ }
+ if (param.primary()) {
+ // if primary then it's an operand
+ report.getTopMessagePart().addProperty(paramName + "_operand",
+ model.getLocalizedDescription());
+ } else {
+ report.getTopMessagePart().addProperty(paramName,
+ model.getLocalizedDescription());
+ }
+ }
+ }
+
+ private static boolean ok(String s) {
+ return s != null && s.length() > 0;
+ }
+
+ /**
+ * Validate the parameters with the Param annotation. If parameter is
+ * not defined as a Param annotation then it's an invalid option.
+ * If parameter's key is "DEFAULT" then it's a operand.
+ *
+ * @param model command model
+ * @param parameters parameters from URL
+ *
+ */
+ static void validateParameters(final CommandModel model,
+ final ParameterMap parameters) throws MultiException {
+
+ ParameterMap adds = null; // renamed password parameters
+
+ // loop through parameters and make sure they are
+ // part of the Param declared field
+ for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
+ String key = entry.getKey();
+
+ // to do, we should validate meta-options differently.
+ if (key.equals("DEFAULT")) {
+ continue;
+ }
+
+ // help and Xhelp are meta-options that are handled specially
+ if (key.equals("help") || key.equals("Xhelp") || key.equals("notify")) {
+ continue;
+ }
+
+ if (key.startsWith(OLD_PASSWORD_PARAM_PREFIX)) {
+ // This is an old prefixed password parameter being passed in.
+ // Strip the prefix and lowercase the name
+ key = key.substring(OLD_PASSWORD_PARAM_PREFIX.length()).toLowerCase(Locale.ENGLISH);
+ if (adds == null) adds = new ParameterMap();
+ adds.add(key, entry.getValue().get(0));
+ }
+
+ // check if key is a valid Param Field
+ boolean validOption = false;
+ // loop through the Param field in the command class
+ // if either field name or the param name is equal to
+ // key then it's a valid option
+ for (CommandModel.ParamModel pModel : model.getParameters()) {
+ validOption = pModel.isParamId(key);
+ if (validOption) {
+ break;
+ }
+ }
+
+ if (!validOption) {
+ throw new MultiException(new IllegalArgumentException(" Invalid option: " + key));
+ }
+ }
+ parameters.mergeAll(adds);
+ }
+
+ /**
+ * Check if the variable, "skipParamValidation" is defined in the command
+ * class. If defined and set to true, then parameter validation will be
+ * skipped from that command.
+ * This is used mostly for command referencing. For example the
+ * list-applications command references list-components command and you
+ * don't want to define the same params from the class that implements
+ * list-components.
+ *
+ * @param command - AdminCommand class
+ * @return true if to skip param validation, else return false.
+ */
+ static boolean skipValidation(AdminCommand command) {
+ try {
+ final Field f =
+ command.getClass().getDeclaredField("skipParamValidation");
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+
+ @Override
+ public Object run() {
+ f.setAccessible(true);
+ return null;
+ }
+ });
+ if (f.getType().isAssignableFrom(boolean.class)) {
+ return f.getBoolean(command);
+ }
+ } catch (NoSuchFieldException e) {
+ return false;
+ } catch (IllegalAccessException e) {
+ return false;
+ }
+ //all else return false
+ return false;
+ }
+
+ private static String encodeManPage(BufferedReader br) {
+ if (br == null) {
+ return null;
+ }
+
+ try {
+ String line;
+ StringBuilder sb = new StringBuilder();
+
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ sb.append(ManifestUtils.EOL_TOKEN);
+ }
+ return sb.toString();
+ } catch (Exception ex) {
+ return null;
+ } finally {
+ try {
+ br.close();
+ } catch (IOException ioex) {
+ }
+ }
+ }
+
+ private static CommandModel getModel(AdminCommand command) {
+
+ if (command instanceof CommandModelProvider) {
+ return ((CommandModelProvider) command).getModel();
+ } else {
+ return new CommandModelImpl(command.getClass());
+ }
+ }
+
+ /**
+ * Called from ExecutionContext.execute.
+ */
+ private void doCommand(ExecutionContext inv, AdminCommand command,
+ final Subject subject, final Job job) {
+
+ boolean fromCheckpoint = job != null &&
+ (job.getState() == AdminCommandState.State.REVERTING ||
+ job.getState() == AdminCommandState.State.FAILED_RETRYABLE);
+ CommandModel model;
+ try {
+ CommandModelProvider c = CommandModelProvider.class.cast(command);
+ model = c.getModel();
+ } catch (ClassCastException e) {
+ model = new CommandModelImpl(command.getClass());
+ }
+ UploadedFilesManager ufm = null;
+ ActionReport report = inv.report();
+ if (!fromCheckpoint) {
+ report.setActionDescription(model.getCommandName() + " command");
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+ ParameterMap parameters;
+ final AdminCommandContext context = new AdminCommandContextImpl(
+ logger, report, inv.inboundPayload(), inv.outboundPayload(),
+ job.getEventBroker(),
+ job.getId());
+ context.setSubject(subject);
+ List<RuntimeType> runtimeTypes = new ArrayList<RuntimeType>();
+ FailurePolicy fp = null;
+ Set<CommandTarget> targetTypesAllowed = new HashSet<CommandTarget>();
+ ActionReport.ExitCode preSupplementalReturn = ActionReport.ExitCode.SUCCESS;
+ ActionReport.ExitCode postSupplementalReturn = ActionReport.ExitCode.SUCCESS;
+ CommandRunnerProgressHelper progressHelper =
+ new CommandRunnerProgressHelper(command, model.getCommandName(), job, inv.progressStatusChild);
+
+ // If this glassfish installation does not have stand alone instances / clusters at all, then
+ // lets not even look Supplemental command and such. A small optimization
+ boolean doReplication = false;
+ if ((domain.getServers().getServer().size() > 1) || (!domain.getClusters().getCluster().isEmpty())) {
+ doReplication = true;
+ } else {
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.devmode",
+ "The GlassFish environment does not have any clusters or instances present; Replication is turned off"));
+ }
+ try {
+ //Get list of suplemental commands
+ Collection<SupplementalCommand> suplementalCommands =
+ supplementalExecutor.listSuplementalCommands(model.getCommandName());
+ try {
+ /*
+ * Extract any uploaded files and build a map from parameter names
+ * to the corresponding extracted, uploaded file.
+ */
+ ufm = new UploadedFilesManager(inv.report, logger,
+ inv.inboundPayload());
+
+ if (inv.typedParams() != null) {
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.delegatedcommand",
+ "This command is a delegated command. Dynamic reconfiguration will be bypassed"));
+ InjectionResolver<Param> injectionTarget =
+ new DelegatedInjectionResolver(model, inv.typedParams(),
+ ufm.optionNameToFileMap());
+ if (injectParameters(model, command, injectionTarget, report)) {
+ inv.setReport(doCommand(model, command, context, progressHelper));
+ }
+ return;
+ }
+
+ parameters = inv.parameters();
+ if (parameters == null) {
+ // no parameters, pass an empty collection
+ parameters = new ParameterMap();
+ }
+
+ if (isSet(parameters, "help") || isSet(parameters, "Xhelp")) {
+ BufferedReader in = getManPage(model.getCommandName(), model);
+ String manPage = encodeManPage(in);
+
+ if (manPage != null && isSet(parameters, "help")) {
+ inv.report().getTopMessagePart().addProperty("MANPAGE", manPage);
+ } else {
+ report.getTopMessagePart().addProperty(
+ AdminCommandResponse.GENERATED_HELP, "true");
+ getHelp(command, report);
+ }
+ return;
+ }
+
+ try {
+ if (!fromCheckpoint && !skipValidation(command)) {
+ validateParameters(model, parameters);
+ }
+ } catch (MultiException e) {
+ // If the cause is UnacceptableValueException -- we want the message
+ // from it. It is wrapped with a less useful Exception.
+
+ Exception exception = e;
+ for (Throwable cause : e.getErrors()) {
+ if (cause != null
+ && (cause instanceof UnacceptableValueException)) {
+ // throw away the wrapper.
+ exception = (Exception) cause;
+ break;
+ }
+
+ }
+
+ logger.log(Level.SEVERE, KernelLoggerInfo.invocationException, exception);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(exception.getMessage());
+ report.setFailureCause(exception);
+ ActionReport.MessagePart childPart =
+ report.getTopMessagePart().addChild();
+ childPart.setMessage(getUsageText(model));
+ return;
+ }
+
+ // initialize the injector and inject
+ MapInjectionResolver injectionMgr =
+ new MapInjectionResolver(model, parameters,
+ ufm.optionNameToFileMap());
+ injectionMgr.setContext(context);
+ if (!injectParameters(model, command, injectionMgr, report)) {
+ return;
+ }
+
+ CommandSupport.init(habitat, command, context, job);
+
+ /*
+ * Now that parameters have been injected into the command object,
+ * decide if the current Subject should be permitted to execute
+ * the command. We need to wait until after injection is done
+ * because the class might implement its own authorization check
+ * and that logic might need the injected values.
+ */
+ final Map<String,Object> env = buildEnvMap(parameters);
+ try {
+ if ( ! commandSecurityChecker.authorize(context.getSubject(), env, command, context)) {
+ /*
+ * If the command class tried to prepare itself but
+ * could not then the return is false and the command has
+ * set the action report accordingly. Don't process
+ * the command further and leave the action report alone.
+ */
+ return;
+ }
+ } catch (SecurityException ex) {
+ report.setFailureCause(ex);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(adminStrings.getLocalString("commandrunner.noauth",
+ "User is not authorized for this command"));
+ return;
+ } catch (Exception ex) {
+ report.setFailureCause(ex);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(adminStrings.getLocalString("commandrunner.errAuth",
+ "Error during authorization"));
+ return;
+ }
+
+
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.injectiondone",
+ "Parameter mapping, validation, injection completed successfully; Starting paramater injection"));
+
+ // Read cluster annotation attributes
+ org.glassfish.api.admin.ExecuteOn clAnnotation = model.getClusteringAttributes();
+ if (clAnnotation == null) {
+ runtimeTypes.add(RuntimeType.DAS);
+ runtimeTypes.add(RuntimeType.INSTANCE);
+ fp = FailurePolicy.Error;
+ } else {
+ if (clAnnotation.value().length == 0) {
+ runtimeTypes.add(RuntimeType.DAS);
+ runtimeTypes.add(RuntimeType.INSTANCE);
+ } else {
+ runtimeTypes.addAll(Arrays.asList(clAnnotation.value()));
+ }
+ if (clAnnotation.ifFailure() == null) {
+ fp = FailurePolicy.Error;
+ } else {
+ fp = clAnnotation.ifFailure();
+ }
+ }
+ TargetType tgtTypeAnnotation = command.getClass().getAnnotation(TargetType.class);
+
+ //@ExecuteOn(RuntimeType.SINGLE_INSTANCE) cannot be combined with
+ //@TargetType since we do not want to replicate the command
+ if (runtimeTypes.contains(RuntimeType.SINGLE_INSTANCE)) {
+ if (tgtTypeAnnotation != null) {
+
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.targettype.unallowed",
+ "Target type is not allowed on single instance command {0} ,"
+ , model.getCommandName()));
+ return;
+ }
+ //Do not replicate the command when there is
+ //@ExecuteOn(RuntimeType.SINGLE_INSTANCE)
+ doReplication = false;
+ }
+
+ String targetName = parameters.getOne("target");
+ if (targetName == null || model.getModelFor("target").getParam().obsolete()) {
+ if (command instanceof DeploymentTargetResolver) {
+ targetName = ((DeploymentTargetResolver) command).getTarget(parameters);
+ } else {
+ targetName = "server";
+ }
+ }
+
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.target",
+ "@ExecuteOn parsing and default settings done; Current target is {0}", targetName));
+
+ if (serverEnv.isDas()) {
+
+ //Do not replicate this command if it has @ExecuteOn(RuntimeType.SINGLE_INSTANCE)
+ //and the user is authorized to execute on DAS
+ // TODO add authorization check
+ /*if (runtimeTypes.contains(RuntimeType.SINGLE_INSTANCE)) {
+ //If authorization fails
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.das.unallowed",
+ "Not authorized to execute command {0} on DAS"
+ , model.getCommandName()));
+ progressHelper.complete(context);
+ return;
+ }*/
+
+ // Check if the command allows this target type; first read the annotation
+ //TODO : See is @TargetType can also be moved to the CommandModel
+
+ if (tgtTypeAnnotation != null) {
+ targetTypesAllowed.addAll(Arrays.asList(tgtTypeAnnotation.value()));
+ }
+ //If not @TargetType, default it
+ if (targetTypesAllowed.isEmpty()) {
+ targetTypesAllowed.add(CommandTarget.DAS);
+ targetTypesAllowed.add(CommandTarget.STANDALONE_INSTANCE);
+ targetTypesAllowed.add(CommandTarget.CLUSTER);
+ targetTypesAllowed.add(CommandTarget.CONFIG);
+ }
+
+ // If the target is "server" and the command is not marked for DAS,
+ // add DAS to RuntimeTypes; This is important because those class of CLIs that
+ // do not always have to be run on DAS followed by applicable instances
+ // will have @ExecuteOn(RuntimeType.INSTANCE) and they have to be run on DAS
+ // ONLY if the target is "server"
+ if (CommandTarget.DAS.isValid(habitat, targetName)
+ && !runtimeTypes.contains(RuntimeType.DAS)) {
+ runtimeTypes.add(RuntimeType.DAS);
+ }
+
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.runtimeTypes",
+ "RuntimeTypes are: {0}", runtimeTypes.toString()));
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration,diagnostics.targetTypes",
+ "TargetTypes are: {0}", targetTypesAllowed.toString()));
+
+ // Check if the target is valid
+ //Is there a server or a cluster or a config with given name ?
+ if ((!CommandTarget.DOMAIN.isValid(habitat, targetName))
+ && (domain.getServerNamed(targetName) == null)
+ && (domain.getClusterNamed(targetName) == null)
+ && (domain.getConfigNamed(targetName) == null)) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.invalidtarget",
+ "Unable to find a valid target with name {0}", targetName));
+ return;
+ }
+ //Does this command allow this target type
+ boolean isTargetValidType = false;
+ Iterator<CommandTarget> it = targetTypesAllowed.iterator();
+ while (it.hasNext()) {
+ if (it.next().isValid(habitat, targetName)) {
+ isTargetValidType = true;
+ break;
+ }
+ }
+ if (!isTargetValidType) {
+ StringBuilder validTypes = new StringBuilder();
+ it = targetTypesAllowed.iterator();
+ while (it.hasNext()) {
+ validTypes.append(it.next().getDescription()).append(", ");
+ }
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.invalidtargettype",
+ "Target {0} is not a supported type. Command {1} supports these types of targets only : {2}",
+ targetName, model.getCommandName(), validTypes.toString()));
+ return;
+ }
+ //If target is a clustered instance and the allowed types does not allow operations on clustered
+ //instance, return error
+ if ((CommandTarget.CLUSTERED_INSTANCE.isValid(habitat, targetName))
+ && (!targetTypesAllowed.contains(CommandTarget.CLUSTERED_INSTANCE))) {
+ Cluster c = domain.getClusterForInstance(targetName);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.instanceopnotallowed",
+ "The {0} command is not allowed on instance {1} because it is part of cluster {2}",
+ model.getCommandName(), targetName, c.getName()));
+ return;
+ }
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.replicationvalidationdone",
+ "All @ExecuteOn attribute and type validation completed successfully. Starting replication stages"));
+ }
+
+ /**
+ * We're finally ready to actually execute the command instance.
+ * Acquire the appropriate lock.
+ */
+ Lock lock = null;
+ boolean lockTimedOut = false;
+ try {
+ // XXX: The owner of the lock should not be hardcoded. The
+ // value is not used yet.
+ lock = adminLock.getLock(command, "asadmin");
+
+ //Set there progress statuses
+ if (!fromCheckpoint) {
+ for (SupplementalCommand supplementalCommand : suplementalCommands) {
+ progressHelper.addProgressStatusToSupplementalCommand(supplementalCommand);
+ }
+ }
+
+ // If command is undoable, then invoke prepare method
+ if (command instanceof UndoableCommand) {
+ UndoableCommand uCmd = (UndoableCommand) command;
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.prepareunodable",
+ "Command execution stage 1 : Calling prepare for undoable command {0}", inv.name()));
+ if (!uCmd.prepare(context, parameters).equals(ActionReport.ExitCode.SUCCESS)) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.errorinprepare",
+ "The command {0} cannot be completed because the preparation for the command failed "
+ + "indicating potential issues : {1}", model.getCommandName(), report.getMessage()));
+ return;
+ }
+ }
+
+ ClusterOperationUtil.clearInstanceList();
+
+ // Run Supplemental commands that have to run before this command on this instance type
+ if (!fromCheckpoint) {
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.presupplemental",
+ "Command execution stage 2 : Call pre supplemental commands for {0}", inv.name()));
+ preSupplementalReturn = supplementalExecutor.execute(suplementalCommands,
+ Supplemental.Timing.Before, context, parameters, ufm.optionNameToFileMap());
+ if (preSupplementalReturn.equals(ActionReport.ExitCode.FAILURE)) {
+ report.setActionExitCode(preSupplementalReturn);
+ if (!StringUtils.ok(report.getTopMessagePart().getMessage())) {
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.supplementalcmdfailed",
+ "A supplemental command failed; cannot proceed further"));
+ }
+ return;
+ }
+ }
+
+ //Run main command if it is applicable for this instance type
+ if ((runtimeTypes.contains(RuntimeType.ALL))
+ || (serverEnv.isDas() &&
+ (CommandTarget.DOMAIN.isValid(habitat, targetName) || runtimeTypes.contains(RuntimeType.DAS)))
+ || runtimeTypes.contains(RuntimeType.SINGLE_INSTANCE)
+ || (serverEnv.isInstance() && runtimeTypes.contains(RuntimeType.INSTANCE))) {
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.maincommand",
+ "Command execution stage 3 : Calling main command implementation for {0}", inv.name()));
+ report = doCommand(model, command, context, progressHelper);
+ inv.setReport(report);
+ }
+
+
+
+ if (!FailurePolicy.applyFailurePolicy(fp,
+ report.getActionExitCode()).equals(ActionReport.ExitCode.FAILURE)) {
+ //Run Supplemental commands that have to be run after this command on this instance type
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.postsupplemental",
+ "Command execution stage 4 : Call post supplemental commands for {0}", inv.name()));
+ postSupplementalReturn = supplementalExecutor.execute(suplementalCommands,
+ Supplemental.Timing.After, context, parameters, ufm.optionNameToFileMap());
+ if (postSupplementalReturn.equals(ActionReport.ExitCode.FAILURE)) {
+ report.setActionExitCode(postSupplementalReturn);
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.supplementalcmdfailed",
+ "A supplemental command failed; cannot proceed further"));
+ return;
+ }
+ }
+ } catch (AdminCommandLockTimeoutException ex) {
+ lockTimedOut = true;
+ String lockTime = formatSuspendDate(ex.getTimeOfAcquisition());
+ String logMsg = "Command: " + model.getCommandName()
+ + " failed to acquire a command lock. REASON: time out "
+ + "(current lock acquired on " + lockTime + ")";
+ String msg = adminStrings.getLocalString("lock.timeout",
+ "Command timed out. Unable to acquire a lock to access "
+ + "the domain. Another command acquired exclusive access "
+ + "to the domain on {0}. Retry the command at a later "
+ + "time.", lockTime);
+ report.setMessage(msg);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ } catch (AdminCommandLockException ex) {
+ lockTimedOut = true;
+ String lockTime = formatSuspendDate(ex.getTimeOfAcquisition());
+ String lockMsg = ex.getMessage();
+ String logMsg;
+
+ logMsg = "Command: " + model.getCommandName()
+ + " was blocked. The domain was suspended by a "
+ + "user on:" + lockTime;
+
+ if (lockMsg != null && !lockMsg.isEmpty()) {
+ logMsg += " Reason: " + lockMsg;
+ }
+
+ String msg = adminStrings.getLocalString("lock.notacquired",
+ "The command was blocked. The domain was suspended by "
+ + "a user on {0}.", lockTime);
+
+ if (lockMsg != null && !lockMsg.isEmpty()) {
+ msg += " "
+ + adminStrings.getLocalString("lock.reason", "Reason:")
+ + " " + lockMsg;
+ }
+
+ report.setMessage(msg);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ } finally {
+ // command is done, release the lock
+ if (lock != null && lockTimedOut == false) {
+ lock.unlock();
+ }
+ }
+
+ } catch (Exception ex) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.invocationException, ex);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(ex.getMessage());
+ report.setFailureCause(ex);
+ ActionReport.MessagePart childPart =
+ report.getTopMessagePart().addChild();
+ childPart.setMessage(getUsageText(model));
+ return;
+ }
+ /*
+ * Command execution completed; If this is DAS and the command succeeded,
+ * time to replicate; At this point we will get the appropriate ClusterExecutor
+ * and give it complete control; We will let the executor take care all considerations
+ * (like FailurePolicy settings etc)
+ * and just give the final execution results which we will set as is in the Final
+ * Action report returned to the caller.
+ */
+
+ if (processEnv.getProcessType().isEmbedded()) {
+ return;
+ }
+ if (preSupplementalReturn == ActionReport.ExitCode.WARNING
+ || postSupplementalReturn == ActionReport.ExitCode.WARNING) {
+ report.setActionExitCode(ActionReport.ExitCode.WARNING);
+ }
+ if (doReplication
+ && (!FailurePolicy.applyFailurePolicy(fp, report.getActionExitCode()).equals(ActionReport.ExitCode.FAILURE))
+ && (serverEnv.isDas())
+ && (runtimeTypes.contains(RuntimeType.INSTANCE) || runtimeTypes.contains(RuntimeType.ALL))) {
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.startreplication",
+ "Command execution stages completed on DAS; Starting replication on remote instances"));
+ ClusterExecutor executor = null;
+ // This try-catch block is a fix for 13838
+ try {
+ if (model.getClusteringAttributes() != null && model.getClusteringAttributes().executor() != null) {
+ executor = habitat.getService(model.getClusteringAttributes().executor());
+ } else {
+ executor = habitat.getService(ClusterExecutor.class, "GlassFishClusterExecutor");
+ }
+ } catch (UnsatisfiedDependencyException usdepex) {
+ logger.log(Level.WARNING, KernelLoggerInfo.cantGetClusterExecutor, usdepex);
+ }
+ if (executor != null) {
+ report.setActionExitCode(executor.execute(model.getCommandName(), command, context, parameters));
+ if (report.getActionExitCode().equals(ActionReport.ExitCode.FAILURE)) {
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.errorwhilereplication",
+ "An error occurred during replication"));
+ } else {
+ if (!FailurePolicy.applyFailurePolicy(fp,
+ report.getActionExitCode()).equals(ActionReport.ExitCode.FAILURE)) {
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.afterreplsupplemental",
+ "Command execution stage 5 : Call post-replication supplemental commands for {0}", inv.name()));
+ ActionReport.ExitCode afterReplicationSupplementalReturn = supplementalExecutor.execute(suplementalCommands,
+ Supplemental.Timing.AfterReplication, context, parameters, ufm.optionNameToFileMap());
+ if (afterReplicationSupplementalReturn.equals(ActionReport.ExitCode.FAILURE)) {
+ report.setActionExitCode(afterReplicationSupplementalReturn);
+ report.setMessage(adminStrings.getLocalString("commandrunner.executor.supplementalcmdfailed",
+ "A supplemental command failed; cannot proceed further"));
+ return;
+ }
+ }
+ }
+ }
+ }
+ if (report.getActionExitCode().equals(ActionReport.ExitCode.FAILURE)) {
+ // If command is undoable, then invoke undo method method
+ if (command instanceof UndoableCommand) {
+ UndoableCommand uCmd = (UndoableCommand) command;
+ logger.fine(adminStrings.getLocalString("dynamicreconfiguration.diagnostics.undo",
+ "Command execution failed; calling undo() for command {0}", inv.name()));
+ uCmd.undo(context, parameters, ClusterOperationUtil.getCompletedInstances());
+ }
+ } else {
+ //TODO : Is there a better way of doing this ? Got to look into it
+ if ("_register-instance".equals(model.getCommandName())) {
+ state.addServerToStateService(parameters.getOne("DEFAULT"));
+ }
+ if ("_unregister-instance".equals(model.getCommandName())) {
+ state.removeInstanceFromStateService(parameters.getOne("DEFAULT"));
+ }
+ }
+ } finally {
+ if (ufm != null) {
+ ufm.close();
+ }
+ }
+ }
+
+ private Map<String,Object> buildEnvMap(final ParameterMap params) {
+ final Map<String,Object> result = new HashMap<String,Object>();
+ for (Map.Entry<String,List<String>> entry : params.entrySet()) {
+ final List<String> values = entry.getValue();
+ if (values != null && values.size() > 0) {
+ result.put(entry.getKey(), values.get(0));
+ }
+ }
+ return result;
+ }
+
+ public void executeFromCheckpoint(JobManager.Checkpoint checkpoint, boolean revert, AdminCommandEventBroker eventBroker) {
+ ExecutionContext ec = new ExecutionContext(null, null, null, null,false);
+ ec.executeFromCheckpoint(checkpoint, revert, eventBroker);
+ }
+
+ /*
+ * Some private classes used in the implementation of CommandRunner.
+ */
+ /**
+ * ExecutionContext is a CommandInvocation, which
+ * defines a command excecution context like the requested
+ * name of the command to execute, the parameters of the command, etc.
+ */
+ class ExecutionContext implements CommandInvocation {
+
+ private class NameListerPair {
+
+ private String nameRegexp;
+ private AdminCommandEventBroker.AdminCommandListener listener;
+
+ public NameListerPair(String nameRegexp, AdminCommandListener listener) {
+ this.nameRegexp = nameRegexp;
+ this.listener = listener;
+ }
+
+ }
+
+ protected String scope;
+ protected String name;
+ protected ActionReport report;
+ protected ParameterMap params;
+ protected CommandParameters paramObject;
+ protected Payload.Inbound inbound;
+ protected Payload.Outbound outbound;
+ protected Subject subject;
+ protected ProgressStatus progressStatusChild;
+ protected boolean isManagedJob;
+ protected boolean isNotify;
+ private List<NameListerPair> nameListerPairs = new ArrayList<NameListerPair>();
+
+ private ExecutionContext(String scope, String name, ActionReport report, Subject subject, boolean isNotify) {
+ this.scope = scope;
+ this.name = name;
+ this.report = report;
+ this.subject = subject;
+ this.isNotify = isNotify;
+ }
+
+ @Override
+ public CommandInvocation parameters(CommandParameters paramObject) {
+ this.paramObject = paramObject;
+ return this;
+ }
+
+ @Override
+ public CommandInvocation parameters(ParameterMap params) {
+ this.params = params;
+ return this;
+ }
+
+ @Override
+ public CommandInvocation inbound(Payload.Inbound inbound) {
+ this.inbound = inbound;
+ return this;
+ }
+
+ @Override
+ public CommandInvocation outbound(Payload.Outbound outbound) {
+ this.outbound = outbound;
+ return this;
+ }
+
+ @Override
+ public CommandInvocation listener(String nameRegexp, AdminCommandEventBroker.AdminCommandListener listener) {
+ nameListerPairs.add(new NameListerPair(nameRegexp, listener));
+ return this;
+ }
+
+ @Override
+ public CommandInvocation progressStatusChild(ProgressStatus ps) {
+ this.progressStatusChild = ps;
+ return this;
+ }
+
+ @Override
+ public CommandInvocation managedJob() {
+ this.isManagedJob = true;
+ return this;
+ }
+
+ @Override
+ public void execute() {
+ execute(null);
+ }
+
+ private ParameterMap parameters() {
+ return params;
+ }
+
+ private CommandParameters typedParams() {
+ return paramObject;
+ }
+
+ private String name() {
+ return name;
+ }
+
+ private String scope() {
+ return scope;
+ }
+
+ @Override
+ public ActionReport report() {
+ return report;
+ }
+
+ private void setReport(ActionReport ar) {
+ report = ar;
+ }
+
+ private Payload.Inbound inboundPayload() {
+ return inbound;
+ }
+
+ private Payload.Outbound outboundPayload() {
+ return outbound;
+ }
+
+ private void executeFromCheckpoint(JobManager.Checkpoint checkpoint, boolean revert, AdminCommandEventBroker eventBroker) {
+ Job job = checkpoint.getJob();
+ if (subject == null) {
+ subject = checkpoint.getContext().getSubject();
+ }
+ parameters(job.getParameters());
+ AdminCommandContext context = checkpoint.getContext();
+ this.report = context.getActionReport();
+ this.inbound = context.getInboundPayload();
+ this.outbound = context.getOutboundPayload();
+ this.scope = job.getScope();
+ this.name = job.getName();
+ if (eventBroker == null) {
+ eventBroker = job.getEventBroker() == null ? new AdminCommandEventBrokerImpl() : job.getEventBroker();
+ }
+ ((AdminCommandInstanceImpl) job).setEventBroker(eventBroker);
+ ((AdminCommandInstanceImpl) job).setState(revert ? AdminCommandState.State.REVERTING : AdminCommandState.State.RUNNING_RETRYABLE);
+ JobManager jobManager = habitat.getService(JobManagerService.class);
+ jobManager.registerJob(job);
+ //command
+ AdminCommand command = checkpoint.getCommand();
+ if (command == null) {
+ command = getCommand(job.getScope(), job.getName(), report(), logger);
+ if (command == null) {
+ return;
+ }
+ }
+ //execute
+ CommandRunnerImpl.this.doCommand(this, command, subject, job);
+ job.complete(report(), outboundPayload());
+ if (progressStatusChild != null) {
+ progressStatusChild.complete();
+ }
+ CommandSupport.done(habitat, command, job);
+ }
+
+ @Override
+ public void execute(AdminCommand command) {
+ if (command == null) {
+ command = getCommand(scope(), name(), report(), logger);
+ if (command == null) {
+ return;
+ }
+ }
+ /*
+ * The caller should have set the subject explicitly. In case
+ * it didn't, try setting it from the current access controller context
+ * since the command framework will have set that before invoking
+ * the original command's execute method.
+ */
+ if (subject == null) {
+ subject = AccessController.doPrivileged(new PrivilegedAction<Subject>() {
+ @Override
+ public Subject run() {
+ return Subject.getSubject(AccessController.getContext());
+ }
+ });
+ }
+
+ if(!isManagedJob) {
+ isManagedJob = AnnotationUtil.presentTransitive(ManagedJob.class, command.getClass());
+ }
+ JobCreator jobCreator = null;
+ JobManager jobManager = null;
+
+ jobCreator = habitat.getService(JobCreator.class,scope+"job-creator");
+ jobManager = habitat.getService(JobManagerService.class);
+
+ if (jobCreator == null ) {
+ jobCreator = habitat.getService(JobCreatorService.class);
+
+ }
+
+ Job job = null;
+ if (isManagedJob) {
+ job = jobCreator.createJob(jobManager.getNewId(), scope(), name(), subject, isManagedJob, parameters());
+ } else {
+ job = jobCreator.createJob(null, scope(), name(), subject, isManagedJob, parameters());
+ }
+
+ //Register the brokers else the detach functionality will not work
+ for (NameListerPair nameListerPair : nameListerPairs) {
+ job.getEventBroker().registerListener(nameListerPair.nameRegexp, nameListerPair.listener);
+ }
+
+ if (isManagedJob) {
+ jobManager.registerJob(job);
+ }
+ CommandRunnerImpl.this.doCommand(this, command, subject, job);
+ job.complete(report(), outboundPayload());
+ if (progressStatusChild != null) {
+ progressStatusChild.complete();
+ }
+ CommandSupport.done(habitat, command, job, isNotify);
+ }
+ }
+
+ /**
+ * An InjectionResolver that uses an Object as the source of
+ * the data to inject.
+ */
+ private static class DelegatedInjectionResolver
+ extends InjectionResolver<Param> {
+
+ private final CommandModel model;
+ private final CommandParameters parameters;
+ private final MultiMap<String, File> optionNameToUploadedFileMap;
+
+ public DelegatedInjectionResolver(CommandModel model,
+ CommandParameters parameters,
+ final MultiMap<String, File> optionNameToUploadedFileMap) {
+ super(Param.class);
+ this.model = model;
+ this.parameters = parameters;
+ this.optionNameToUploadedFileMap = optionNameToUploadedFileMap;
+
+ }
+
+ @Override
+ public boolean isOptional(AnnotatedElement element, Param annotation) {
+ String name = CommandModel.getParamName(annotation, element);
+ CommandModel.ParamModel param = model.getModelFor(name);
+ return param.getParam().optional();
+ }
+
+ @Override
+ public <V> V getValue(Object component, AnnotatedElement target, Type genericType, Class<V> type) {
+
+ // look for the name in the list of parameters passed.
+ if (target instanceof Field) {
+ final Field targetField = (Field) target;
+ try {
+ Field sourceField =
+ parameters.getClass().getField(targetField.getName());
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+
+ @Override
+ public Object run() {
+ targetField.setAccessible(true);
+ return null;
+ }
+ });
+ Object paramValue = sourceField.get(parameters);
+
+ /*
+ * If this field is a File, then replace the param value
+ * (which is whatever the client supplied on the command) with
+ * the actual absolute path(s) of the uploaded and extracted
+ * file(s) if, in fact, the file(s) was (were) uploaded.
+ */
+
+ final List<String> paramFileValues =
+ MapInjectionResolver.getUploadedFileParamValues(
+ targetField.getName(),
+ targetField.getType(),
+ optionNameToUploadedFileMap);
+ if (!paramFileValues.isEmpty()) {
+ V fileValue = (V) MapInjectionResolver.convertListToObject(target, type, paramFileValues);
+ return fileValue;
+ }
+ /*
+ if (paramValue==null) {
+ return convertStringToObject(target, type,
+ param.defaultValue());
+ }
+ */
+ // XXX temp fix, to revisit
+ if (paramValue != null) {
+ checkAgainstAcceptableValues(target,
+ paramValue.toString());
+ }
+ return type.cast(paramValue);
+ } catch (IllegalAccessException e) {
+ } catch (NoSuchFieldException e) {
+ }
+ }
+ return null;
+ }
+
+ private static void checkAgainstAcceptableValues(
+ AnnotatedElement target, String paramValueStr) {
+ Param param = target.getAnnotation(Param.class);
+ String acceptable = param.acceptableValues();
+ String paramName = CommandModel.getParamName(param, target);
+
+ if (ok(acceptable) && ok(paramValueStr)) {
+ String[] ss = acceptable.split(",");
+
+ for (String s : ss) {
+ if (paramValueStr.equals(s.trim())) {
+ return; // matched, value is good
+ }
+ }
+
+ // didn't match any, error
+ throw new UnacceptableValueException(
+ adminStrings.getLocalString(
+ "adapter.command.unacceptableValue",
+ "Invalid parameter: {0}. Its value is {1} "
+ + "but it isn''t one of these acceptable values: {2}",
+ paramName,
+ paramValueStr,
+ acceptable));
+ }
+ }
+ }
+
+ /**
+ * Is the boolean valued parameter specified?
+ * If so, and it has a value, is the value "true"?
+ */
+ private static boolean isSet(ParameterMap params, String name) {
+ String val = params.getOne(name);
+ if (val == null) {
+ return false;
+ }
+ return val.length() == 0 || Boolean.valueOf(val).booleanValue();
+ }
+
+ /** Works as a key in ETag cache map
+ */
+ private static class NameCommandClassPair {
+ private String name;
+ private Class<? extends AdminCommand> clazz;
+ private int hash; //immutable, we can cache it
+
+ public NameCommandClassPair(String name, Class<? extends AdminCommand> clazz) {
+ this.name = name;
+ this.clazz = clazz;
+ hash = 3;
+ hash = 67 * hash + (this.name != null ? this.name.hashCode() : 0);
+ hash = 67 * hash + (this.clazz != null ? this.clazz.hashCode() : 0);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final NameCommandClassPair other = (NameCommandClassPair) obj;
+ if (this.clazz != other.clazz) {
+ return false;
+ }
+ if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+ }
+
+ /**
+ * Encapsulates handling of files uploaded to the server in the payload
+ * of the incoming HTTP request.
+ * <p>
+ * Extracts any such files from the payload into a temporary directory
+ * under the domain's applications directory. (Putting them there allows
+ * the deployment processing to rename the uploaded archive to another location
+ * under the applications directory, rather than having to copy them.)
+ */
+ private class UploadedFilesManager {
+
+ private final ActionReport report;
+ private final Logger logger;
+ /**
+ * maps option names as sent with each uploaded file to the corresponding
+ * extracted files
+ */
+ private MultiMap<String, File> optionNameToFileMap;
+
+ /*
+ * PFM needs to be a field so it is not gc-ed before the
+ * UploadedFilesManager is closed.
+ */
+ private PayloadFilesManager.Temp payloadFilesMgr = null;
+
+ private UploadedFilesManager(final ActionReport report,
+ final Logger logger,
+ final Payload.Inbound inboundPayload) throws IOException, Exception {
+ this.logger = logger;
+ this.report = report;
+ extractFiles(inboundPayload);
+ }
+
+ private MultiMap<String, File> optionNameToFileMap() {
+ return optionNameToFileMap;
+ }
+
+ private void close() {
+ if (payloadFilesMgr != null) {
+ payloadFilesMgr.cleanup();
+ }
+ }
+
+ private void extractFiles(final Payload.Inbound inboundPayload)
+ throws Exception {
+ if (inboundPayload == null) {
+ return;
+ }
+
+ final File uniqueSubdirUnderApplications = chooseTempDirParent();
+ payloadFilesMgr = new PayloadFilesManager.Temp(
+ uniqueSubdirUnderApplications,
+ report,
+ logger);
+
+ /*
+ * Extract the files into the temp directory.
+ */
+ final Map<File, Properties> payloadFiles =
+ payloadFilesMgr.processPartsExtended(inboundPayload);
+
+ /*
+ * Prepare the map of command options names to corresponding
+ * uploaded files.
+ */
+ optionNameToFileMap = new MultiMap<String, File>();
+ for (Map.Entry<File, Properties> e : payloadFiles.entrySet()) {
+ final String optionName = e.getValue().getProperty("data-request-name");
+ if (optionName != null) {
+ logger.finer("UploadedFilesManager: map " + optionName
+ + " to " + e.getKey());
+ optionNameToFileMap.add(optionName, e.getKey());
+ }
+ }
+ }
+
+ private File chooseTempDirParent() throws IOException {
+ final File appRoot = new File(domain.getApplicationRoot());
+
+ /*
+ * Apparently during embedded runs the applications directory
+ * might not be present already. Create it if needed.
+ */
+ if (!appRoot.isDirectory()) {
+ if (!appRoot.exists() && !appRoot.mkdirs()) {
+ throw new IOException(adminStrings.getLocalString("commandrunner.errCreDir",
+ "Could not create the directory {0}; no further information is available.",
+ appRoot.getAbsolutePath()));
+ }
+ }
+
+ return appRoot;
+ }
+ }
+
+ /**
+ * Format the lock acquisition time.
+ */
+ private String formatSuspendDate(Date lockTime) {
+ if (lockTime != null) {
+ String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z";
+ SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
+ return sdf.format(lockTime);
+ } else {
+ return adminStrings.getLocalString("lock.timeoutunavailable",
+ "<<Date is unavailable>>");
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CommandRunnerProgressHelper.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CommandRunnerProgressHelper.java
new file mode 100644
index 0000000..91ab4df
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CommandRunnerProgressHelper.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.admin.progress.CommandProgressImpl;
+import com.sun.enterprise.admin.progress.ProgressStatusClient;
+import java.lang.annotation.Annotation;
+import java.util.UUID;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.admin.CommandProgress;
+import org.glassfish.api.admin.SupplementalCommandExecutor.SupplementalCommand;
+import org.glassfish.api.admin.progress.ProgressStatusBase;
+import org.glassfish.api.admin.progress.ProgressStatusEvent;
+import org.glassfish.api.admin.progress.ProgressStatusMirroringImpl;
+import org.glassfish.config.support.GenericCrudCommand;
+
+/** Helper class for {@code ProgressStatus} manipulation during
+ * {@code CommandRunner} execution.<br/><br/>
+ * <b>Life cycle:</b><br/>
+ * <ul>
+ * <li>Constructs</li>
+ * <li>setReplicationCount</li>
+ * <li>addProgressStatusToSupplementalCommand <i>(optional)</i></li>
+ * <li>wrapContext4MainCommand</li>
+ * <li><i>do replication</i></li>
+ * <li>complete</li>
+ * </ul>
+ *
+ * @author mmares
+ */
+class CommandRunnerProgressHelper {
+
+ //From constructor
+ private Progress progressAnnotation;
+ private CommandProgressImpl commandProgress;
+ private int replicationCount = 0;
+
+ //Changed during lifecycle
+ private ProgressStatus progressForMainCommand = null;
+ private ProgressStatusMirroringImpl progressMirroring = null;
+
+ public CommandRunnerProgressHelper(AdminCommand command, String name, Job job, ProgressStatus clientProgressStatus) {
+ if (command instanceof GenericCrudCommand) {
+ GenericCrudCommand gcc = (GenericCrudCommand) command;
+ Class decorator = gcc.getDecoratorClass();
+ if (decorator != null) {
+ progressAnnotation = (Progress) decorator.getAnnotation(Progress.class);
+ }
+ } else if (command instanceof ProgressProvider) {
+ progressAnnotation = ((ProgressProvider) command).getProgress();
+ } else {
+ progressAnnotation = command.getClass().getAnnotation(Progress.class);
+ }
+ this.commandProgress = (CommandProgressImpl) job.getCommandProgress(); //Possible from checkpoint
+ if (progressAnnotation != null) {
+ if (commandProgress == null) {
+ if (progressAnnotation.name() == null || progressAnnotation.name().isEmpty()) {
+ commandProgress = new CommandProgressImpl(name, createIdForCommandProgress(job));
+ } else {
+ commandProgress = new CommandProgressImpl(progressAnnotation.name(), createIdForCommandProgress(job));
+ }
+ }
+ connectWithClientProgressStatus(job, clientProgressStatus);
+ job.setCommandProgress(commandProgress);
+ }
+ }
+
+ private void connectWithClientProgressStatus(Job commandInstance, ProgressStatus clientProgressStatus) {
+ if (clientProgressStatus == null) {
+ return;
+ }
+ final ProgressStatusClient psc = new ProgressStatusClient(clientProgressStatus);
+ commandInstance.getEventBroker().registerListener(CommandProgress.EVENT_PROGRESSSTATUS_STATE, new AdminCommandEventBroker.AdminCommandListener<ProgressStatusBase>() {
+ @Override
+ public void onAdminCommandEvent(String name, ProgressStatusBase event) {
+ psc.mirror(event);
+ }
+ });
+ commandInstance.getEventBroker().registerListener(CommandProgress.EVENT_PROGRESSSTATUS_CHANGE, new AdminCommandEventBroker.AdminCommandListener<ProgressStatusEvent>() {
+ @Override
+ public void onAdminCommandEvent(String name, ProgressStatusEvent event) {
+ psc.mirror(event);
+ }
+ });
+ }
+
+ private String createIdForCommandProgress(Job commandInstance) {
+ String cid = commandInstance == null ? null : commandInstance.getId();
+ if (cid == null || cid.isEmpty()) {
+ cid = UUID.randomUUID().toString();
+ }
+ return cid;
+ }
+
+ public int getReplicationCount() {
+ return replicationCount;
+ }
+
+ public void setReplicationCount(int replicationCount) {
+ this.replicationCount = replicationCount;
+ }
+
+ public void addProgressStatusToSupplementalCommand(SupplementalCommand supplemental) {
+ if (commandProgress == null || supplemental == null) {
+ return;
+ }
+ if (progressForMainCommand != null && progressMirroring == null) {
+ throw new IllegalStateException("Suplmenetal commands must be filled with ProgressStatus before main command!");
+ }
+ if (replicationCount < 0) {
+ throw new IllegalStateException("Replication count must be provided first");
+ }
+ if (supplemental.getProgressAnnotation() != null) {
+ if (progressMirroring == null) {
+ commandProgress.setTotalStepCount(replicationCount + 1);
+ progressMirroring = commandProgress.createMirroringChild(1);
+ progressForMainCommand = progressMirroring.createChild(null, 0, progressAnnotation.totalStepCount());
+ }
+ supplemental.setProgressStatus(progressMirroring.createChild(supplemental.getProgressAnnotation().name(),
+ 0, supplemental.getProgressAnnotation().totalStepCount()));
+ }
+ }
+
+ public AdminCommandContext wrapContext4MainCommand(AdminCommandContext context) {
+ if (progressForMainCommand != null) {
+ return new AdminCommandContextForInstance(context, progressForMainCommand);
+ }
+ if (commandProgress != null) {
+ if (replicationCount > 0) {
+ commandProgress.setTotalStepCount(replicationCount + 1);
+ progressForMainCommand = commandProgress.createChild(null, 1, progressAnnotation.totalStepCount());
+ } else {
+ commandProgress.setTotalStepCount(progressAnnotation.totalStepCount());
+ progressForMainCommand = commandProgress;
+ }
+ return new AdminCommandContextForInstance(context, progressForMainCommand);
+ }
+ return context;
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CompletedJob.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CompletedJob.java
new file mode 100644
index 0000000..15266ff
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CompletedJob.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import java.io.File;
+
+/**
+ * This class stores some data about long running jobs which have completed
+ * It stores job,id,the time of completion
+ * the location of the jobs file
+ * @author Bhakti Mehta
+ */
+public class CompletedJob {
+
+ private final String id;
+
+ private final long completionTime;
+
+ private final File jobsFile;
+
+
+ public CompletedJob(String id, long completionTime, File jobsFile) {
+
+ this.completionTime = completionTime;
+ this.jobsFile = jobsFile;
+ this.id = id;
+ }
+
+ public long getCompletionTime() {
+ return completionTime;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public File getJobsFile() {
+ return jobsFile;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CreateProfiler.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CreateProfiler.java
new file mode 100644
index 0000000..dadf519
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CreateProfiler.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import java.beans.PropertyVetoException;
+import java.util.Map;
+import java.util.Properties;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import com.sun.enterprise.config.serverbeans.Profiler;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.SystemPropertyConstants;
+
+import org.jvnet.hk2.config.types.Property;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import org.glassfish.config.support.TargetType;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.internal.api.Target;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+
+/**
+ * Create Profiler Command
+ *
+ */
+@Service(name="create-profiler")
+@PerLookup
+@I18n("create.profiler")
+@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+@TargetType({CommandTarget.DAS,CommandTarget.STANDALONE_INSTANCE,CommandTarget.CLUSTER,CommandTarget.CONFIG})
+@RestEndpoints({
+ @RestEndpoint(configBean=JavaConfig.class,
+ opType=RestEndpoint.OpType.POST,
+ path="create-profiler",
+ description="Create Profiler")
+})
+public class CreateProfiler implements AdminCommand, AdminCommandSecurity.Preauthorization {
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(CreateProfiler.class);
+
+ @Param(optional=true)
+ String classpath;
+
+ @Param(optional=true, defaultValue="true")
+ Boolean enabled;
+
+ @Param(name="nativelibrarypath", optional=true)
+ String nativeLibraryPath;
+
+ @Param(name="profiler_name", primary=true)
+ String name;
+
+ @Param(name="property", optional=true, separator=':')
+ Properties properties;
+
+ @Param(name="target", optional=true, defaultValue = SystemPropertyConstants.DEFAULT_SERVER_INSTANCE_NAME)
+ String target;
+
+ @Inject
+ Target targetService;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ @AccessRequired.To("update")
+ private JavaConfig javaConfig;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ config = CLIUtil.chooseConfig(targetService, config, target);
+ javaConfig = config.getJavaConfig();
+ return true;
+ }
+
+
+
+ /**
+ * Executes the command with the command parameters passed as Properties
+ * where the keys are the paramter names and the values the parameter values
+ *
+ * @param context information
+ */
+ public void execute(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+
+ if (javaConfig.getProfiler() != null) {
+ System.out.println("profiler exists. Please delete it first");
+ report.setMessage(
+ localStrings.getLocalString("create.profiler.alreadyExists",
+ "profiler exists. Please delete it first"));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+
+ try {
+ ConfigSupport.apply(new SingleConfigCode<JavaConfig>() {
+
+ public Object run(JavaConfig param) throws PropertyVetoException, TransactionFailure {
+ Profiler newProfiler = param.createChild(Profiler.class);
+ newProfiler.setName(name);
+ newProfiler.setClasspath(classpath);
+ newProfiler.setEnabled(enabled.toString());
+ newProfiler.setNativeLibraryPath(nativeLibraryPath);
+ if (properties != null) {
+ for ( Map.Entry e : properties.entrySet()) {
+ Property prop = newProfiler.createChild(Property.class);
+ prop.setName((String)e.getKey());
+ prop.setValue((String)e.getValue());
+ newProfiler.getProperty().add(prop);
+ }
+ }
+ param.setProfiler(newProfiler);
+ return newProfiler;
+ }
+ }, javaConfig);
+
+ } catch(TransactionFailure e) {
+ report.setMessage(localStrings.getLocalString("create.profiler.fail", "{0} create failed ", name));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ }
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CreateSystemProperties.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CreateSystemProperties.java
new file mode 100644
index 0000000..40c2410
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/CreateSystemProperties.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.SystemProperty;
+import com.sun.enterprise.config.serverbeans.SystemPropertyBag;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import java.beans.PropertyVetoException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Properties;
+import javax.inject.Inject;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.AccessRequired;
+import org.glassfish.api.admin.AccessRequired.AccessCheck;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.AdminCommandSecurity;
+import org.glassfish.api.admin.ExecuteOn;
+import org.glassfish.api.admin.RuntimeType;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.Transaction;
+import org.jvnet.hk2.config.TransactionFailure;
+
+/**
+ * Create System Properties Command
+ *
+ * Adds or updates one or more system properties of the domain, configuration,
+ * cluster, or server instance
+ *
+ * Usage: create-system-properties [--terse=false] [--echo=false] [--interactive=true]
+ * [--host localhost] [--port 4848|4849] [--secure|-s=true] [--user admin_user]
+ * [--passwordfile file_name] [--target target(Default server)] (name=value)[:name=value]*
+ *
+ * @author Jennifer Chou
+ *
+ */
+@Service(name="create-system-properties")
+@PerLookup
+@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+@TargetType(value={CommandTarget.CLUSTER,
+CommandTarget.CONFIG, CommandTarget.DAS, CommandTarget.DOMAIN, CommandTarget.STANDALONE_INSTANCE,CommandTarget.CLUSTERED_INSTANCE})
+@I18n("create.system.properties")
+public class CreateSystemProperties implements AdminCommand, AdminCommandSecurity.Preauthorization,
+ AdminCommandSecurity.AccessCheckProvider {
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(CreateSystemProperties.class);
+
+ @Param(optional=true, defaultValue=SystemPropertyConstants.DAS_SERVER_NAME)
+ String target;
+
+ @Param(name="name_value", primary=true, separator=':')
+ Properties properties;
+
+ @Inject
+ Domain domain;
+
+ private SystemPropertyBag spb;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ spb = CLIUtil.chooseTarget(domain, target);
+ if (spb == null) {
+ final ActionReport report = context.getActionReport();
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ String msg = localStrings.getLocalString("invalid.target.sys.props",
+ "Invalid target:{0}. Valid targets types are domain, config, cluster, default server, clustered instance, stand alone instance", target);
+ report.setMessage(msg);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public Collection<? extends AccessCheck> getAccessChecks() {
+ final Collection<AccessCheck> result = new ArrayList<AccessCheck>();
+ result.add(new AccessCheck(AccessRequired.Util.resourceNameFromConfigBeanProxy(spb), "update"));
+ return result;
+ }
+
+ /**
+ * Executes the command with the command parameters passed as Properties
+ * where the keys are the paramter names and the values the parameter values
+ *
+ * @param context information
+ */
+ @Override
+ public void execute(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+
+ String sysPropName = "";
+ try {
+ for (final Object key : properties.keySet()) {
+ final String propName = (String) key;
+ sysPropName = propName;
+
+ // skip create-system property requests that do not change the
+ // value of an existing property
+ if (spb.containsProperty(sysPropName) &&
+ spb.getSystemProperty(sysPropName).getValue().equals(properties.getProperty(propName))) {
+ continue;
+ }
+ ConfigSupport.apply(new SingleConfigCode<SystemPropertyBag>() {
+
+ @Override
+ public Object run(SystemPropertyBag param) throws PropertyVetoException, TransactionFailure {
+
+ // update existing system property
+ for (SystemProperty sysProperty : param.getSystemProperty()) {
+ if (sysProperty.getName().equals(propName)) {
+ Transaction t = Transaction.getTransaction(param);
+ sysProperty = t.enroll(sysProperty);
+ sysProperty.setValue(properties.getProperty(propName));
+ return sysProperty;
+ }
+ }
+
+ // create system-property
+ SystemProperty newSysProp = param.createChild(SystemProperty.class);
+ newSysProp.setName(propName);
+ newSysProp.setValue(properties.getProperty(propName));
+ param.getSystemProperty().add(newSysProp);
+ return newSysProp;
+ }
+ }, spb);
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+ } catch(TransactionFailure tfe) {
+ report.setMessage(localStrings.getLocalString("create.system.properties.failed",
+ "System property {0} creation failed", sysPropName));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(tfe);
+ } catch(Exception e) {
+ report.setMessage(localStrings.getLocalString("create.system.properties.failed",
+ "System property {0} creation failed", sysPropName));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DeleteProfiler.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DeleteProfiler.java
new file mode 100644
index 0000000..a111baa
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DeleteProfiler.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Config;
+
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.ExecuteOn;
+import org.glassfish.api.admin.RuntimeType;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.config.support.TargetType;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.internal.api.Target;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.ActionReport;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import com.sun.enterprise.config.serverbeans.Profiler;
+import com.sun.enterprise.config.serverbeans.SystemPropertyBag;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.SystemPropertyConstants;
+
+import java.beans.PropertyVetoException;
+import java.util.ArrayList;
+import java.util.Collection;
+import org.glassfish.api.admin.*;
+
+/**
+* Delete JDBC Resource command
+*
+*/
+@Service(name="delete-profiler")
+@PerLookup
+@I18n("delete.profiler")
+@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+@TargetType({CommandTarget.DAS,CommandTarget.STANDALONE_INSTANCE,CommandTarget.CLUSTER,CommandTarget.CONFIG})
+@RestEndpoints({
+ @RestEndpoint(configBean=Profiler.class,
+ opType=RestEndpoint.OpType.DELETE,
+ path="delete-profiler",
+ description="Delete Profiler")
+})
+public class DeleteProfiler implements AdminCommand, AdminCommandSecurity.Preauthorization {
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(DeleteProfiler.class);
+
+ @Param(name="target", optional=true, defaultValue = SystemPropertyConstants.DEFAULT_SERVER_INSTANCE_NAME)
+ String target;
+
+ @Inject
+ Target targetService;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ @AccessRequired.To("update")
+ private JavaConfig javaConfig;
+
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ config = CLIUtil.chooseConfig(targetService, config, target);
+ javaConfig = config.getJavaConfig();
+ return true;
+ }
+
+ /**
+ * Executes the command with the command parameters passed as Properties
+ * where the keys are the paramter names and the values the parameter values
+ *
+ * @param context information
+ */
+ public void execute(AdminCommandContext context) {
+
+ final ActionReport report = context.getActionReport();
+ try {
+ ConfigSupport.apply(new SingleConfigCode<JavaConfig>() {
+ public Object run(JavaConfig param) throws PropertyVetoException, TransactionFailure {
+ if (param.getProfiler() != null) {
+ param.setProfiler(null);
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ return param;
+ }
+ // not found
+ report.setMessage(localStrings.getLocalString("delete.profiler.notfound", "delete failed, profiler not found"));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return null;
+ }
+ }, javaConfig);
+ } catch(TransactionFailure e) {
+ report.setMessage(localStrings.getLocalString("delete.profiler.fail", "delete failed "));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DeleteSystemProperty.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DeleteSystemProperty.java
new file mode 100644
index 0000000..8c9c6fa
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DeleteSystemProperty.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.*;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+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.RuntimeType;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+import javax.inject.Inject;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+import org.jvnet.hk2.config.Dom;
+import org.jvnet.hk2.config.types.Property;
+
+import java.beans.PropertyVetoException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import org.glassfish.api.admin.AccessRequired;
+import org.glassfish.api.admin.AdminCommandSecurity;
+
+/**
+ * Delete System Property Command
+ *
+ * Removes one system property of the domain, configuration, cluster, or server
+ * instance, at a time
+ *
+ * Usage: delete-system-property [--terse=false] [--echo=false] [--interactive=true]
+ * [--host localhost] [--port 4848|4849] [--secure|-s=true] [--user admin_user] [
+ * --passwordfile file_name] [--target target(Default server)] property_name
+ *
+ */
+@Service(name="delete-system-property")
+@PerLookup
+@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+@TargetType(value={CommandTarget.CLUSTER, CommandTarget.CLUSTERED_INSTANCE,
+CommandTarget.CONFIG, CommandTarget.DAS, CommandTarget.DOMAIN, CommandTarget.STANDALONE_INSTANCE})
+@I18n("delete.system.property")
+public class DeleteSystemProperty implements AdminCommand,
+ AdminCommandSecurity.Preauthorization, AdminCommandSecurity.AccessCheckProvider {
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(DeleteSystemProperty.class);
+
+ @Param(optional=true, defaultValue=SystemPropertyConstants.DAS_SERVER_NAME)
+ String target;
+
+ @Param(name="property_name", primary=true)
+ String propName;
+
+ @Inject
+ Domain domain;
+
+ private SystemPropertyBag spb;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ spb = CLIUtil.chooseTarget(domain, target);
+ if (spb == null) {
+ final ActionReport report = context.getActionReport();
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ String msg = localStrings.getLocalString("invalid.target.sys.props",
+ "Invalid target:{0}. Valid targets types are domain, config, cluster, default server, clustered instance, stand alone instance", target);
+ report.setMessage(msg);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public Collection<? extends AccessRequired.AccessCheck> getAccessChecks() {
+ final Collection<AccessRequired.AccessCheck> result = new ArrayList<AccessRequired.AccessCheck>();
+ result.add(new AccessRequired.AccessCheck(AccessRequired.Util.resourceNameFromConfigBeanProxy(spb), "update"));
+ return result;
+ }
+
+ /**
+ * Executes the command with the command parameters passed as Properties
+ * where the keys are the paramter names and the values the parameter values
+ *
+ * @param context information
+ */
+ public void execute(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+ Property domainProp = domain.getProperty("administrative.domain.name");
+ String domainName = domainProp.getValue();
+ if(!spb.containsProperty(propName)) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ String msg = localStrings.getLocalString("no.such.property",
+ "System Property named {0} does not exist at the given target {1}", propName, target);
+ report.setMessage(msg);
+ return;
+ }
+ if (definitions(propName) == 1) { //implying user is deleting the "last" definition of this property
+ List<String> refs = new ArrayList<String>();
+ List<Dom> doms = new ArrayList<Dom>();
+ if ("domain".equals(target) || target.equals(domainName)) {
+ for (Server s : domain.getServers().getServer()) {
+ Config config = s.getConfig();
+ Cluster cluster = s.getCluster();
+ if (!s.containsProperty(propName) && !config.containsProperty(propName)) {
+ if (cluster != null) {
+ if (!cluster.containsProperty(propName)) {
+ doms.add(Dom.unwrap(s));
+ }
+ } else {
+ doms.add(Dom.unwrap(s));
+ }
+ }
+ }
+ } else {
+ Config config = domain.getConfigNamed(target);
+ if (config != null) {
+ doms.add(Dom.unwrap(config));
+ String configName = config.getName();
+ for (Server s : domain.getServers().getServer()) {
+ String configRef = s.getConfigRef();
+ if (configRef.equals(configName)) {
+ if (!s.containsProperty(propName)) {
+ doms.add(Dom.unwrap(s));
+ }
+ }
+ }
+ for (Cluster c : domain.getClusters().getCluster()) {
+ String configRef = c.getConfigRef();
+ if (configRef.equals(configName)) {
+ if (!c.containsProperty(propName)) {
+ doms.add(Dom.unwrap(c));
+ }
+ }
+ }
+ } else {
+ Cluster cluster = domain.getClusterNamed(target);
+ if (cluster != null) {
+ doms.add(Dom.unwrap(cluster));
+ Config clusterConfig = domain.getConfigNamed(cluster.getConfigRef());
+ doms.add(Dom.unwrap(clusterConfig));
+ for (Server s : cluster.getInstances()) {
+ if (!s.containsProperty(propName)) {
+ doms.add(Dom.unwrap(s));
+ }
+ }
+ } else {
+ Server server = domain.getServerNamed(target);
+ doms.add(Dom.unwrap(server));
+ doms.add(Dom.unwrap(domain.getConfigNamed(server.getConfigRef())));
+ }
+ }
+ }
+ String sysPropName = SystemPropertyConstants.getPropertyAsValue(propName);
+ for (Dom d : doms) {
+ listRefs(d, sysPropName, refs);
+ }
+ if (!refs.isEmpty()) {
+ //there are some references
+ String msg = localStrings.getLocalString("cant.delete.referenced.property",
+ "System Property {0} is referenced by {1} in the configuration. Please remove the references first.", propName, Arrays.toString(refs.toArray()));
+ report.setMessage(msg);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+ }
+ //now we are sure that the target exits in the config, just remove the given property
+ try {
+ ConfigSupport.apply(new SingleConfigCode<SystemPropertyBag>() {
+ public Object run(SystemPropertyBag param) throws PropertyVetoException, TransactionFailure {
+ param.getSystemProperty().remove(param.getSystemProperty(propName));
+ return param;
+ }
+ }, spb);
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ String msg = localStrings.getLocalString("delete.sysprops.ok",
+ "System Property named {0} deleted from given target {1}. Make sure you check its references.", propName, target);
+ report.setMessage(msg);
+ } catch (TransactionFailure tf) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(tf);
+ }
+ }
+
+ private int definitions(String propName) {
+ //are there multiple <system-property> definitions for the given name?
+ int defs = 0;
+ SystemPropertyBag bag = domain;
+ if (bag.containsProperty(propName))
+ defs++;
+
+ bag = domain.getServerNamed(target);
+ if (bag != null && bag.containsProperty(propName)) {
+ defs++;
+ Server server = (Server)bag;
+ Cluster cluster = server.getCluster();
+ if (cluster != null && cluster.containsProperty(propName))
+ defs++;
+ if (server.getConfig().containsProperty(propName))
+ defs++;
+ }
+
+ bag = domain.getClusterNamed(target);
+ if (bag != null && bag.containsProperty(propName)) {
+ defs++;
+ Cluster c = (Cluster)bag;
+ Config clusterConfig = domain.getConfigNamed(c.getConfigRef());
+ if (clusterConfig.containsProperty(propName))
+ defs++;
+ }
+
+ bag = domain.getConfigNamed(target);
+ if (bag != null && bag.containsProperty(propName))
+ defs++;
+
+ return defs;
+ }
+
+ private static void listRefs(Dom dom, String value, List<String> refs) {
+ //this method is rather ugly, but it works. See 9340 which presents a compatibility issue
+ //frankly, it makes no sense to do an extensive search of all references of <system-property> being deleted,
+ //but that's what resolution of this issue demands. --- Kedar 10/5/2009
+ for (String aname : dom.getAttributeNames()) {
+ String raw = dom.rawAttribute(aname);
+ if (raw != null && raw.equals(value)) {
+ refs.add(dom.model.getTagName() + ":" + aname);
+ }
+ }
+ for (String ename : dom.getElementNames()) {
+ List<Dom> nodes = null;
+ try {
+ nodes = dom.nodeElements(ename);
+ } catch(Exception e) {
+ //ignore, in some situations, HK2 might throw ClassCastException here
+ }
+ if (nodes != null) {
+ for (Dom node : nodes)
+ listRefs(node, value, refs); //beware: recursive call ...
+ }
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DumpHK2Command.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DumpHK2Command.java
new file mode 100644
index 0000000..3871f24
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DumpHK2Command.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.universal.collections.ManifestUtils;
+import com.sun.enterprise.v3.common.PropsFileActionReporter;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.ActionReport.ExitCode;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import org.glassfish.api.admin.AccessRequired;
+import org.glassfish.api.admin.RestEndpoint;
+import org.glassfish.api.admin.RestEndpoints;
+import org.glassfish.hk2.api.PerLookup;
+
+/**
+ * Dumps the currently configured HK2 modules and their contents.
+ *
+ * <p>
+ * Useful for debugging classloader related issues.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+@PerLookup
+@Service(name="_dump-hk2")
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.POST,
+ path="_dump-hk2",
+ description="_dump-hk2")
+})
+@AccessRequired(resource="domain", action="dump")
+public class DumpHK2Command implements AdminCommand {
+
+ @Inject
+ ModulesRegistry modulesRegistry;
+
+ public void execute(AdminCommandContext context) {
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ modulesRegistry.dumpState(new PrintStream(baos));
+
+ ActionReport report = context.getActionReport();
+ report.setActionExitCode(ExitCode.SUCCESS);
+ String msg = baos.toString();
+
+ // the proper way to do this is to check the user-agent of the caller,
+ // but I can't access that -- so I'll just check the type of the
+ // ActionReport. If we are sending back to CLI then linefeeds will
+ // cause problems. Manifest.write() is OK but Manifest.read() explodes!
+ if(report instanceof PropsFileActionReporter) {
+ msg = ManifestUtils.encode(msg);
+ }
+ report.setMessage(msg);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DynamicInterceptor.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DynamicInterceptor.java
new file mode 100755
index 0000000..a9934ba
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/DynamicInterceptor.java
@@ -0,0 +1,848 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.*;
+import javax.management.*;
+import javax.management.loading.ClassLoaderRepository;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+
+/**
+ This Interceptor wraps the real MBeanServer so that additional interceptor code can be
+ "turned on" at a later point. However, it must be possible to start the MBeanServer even before
+ the JVM calls main(). Therefore,
+ <b>This class must not depend on anything that can't initialize before the JVM calls main()</b>.
+ <i>This includes things like logging which is not happy being invoked
+ that early.</i>
+ <p>
+ When instantiated at startup, the instance of this class that wraps the real MBeanServer
+ is termed the "Primary Interceptor". There can only be one such Interceptor for each
+ *real* MBeanServer. MBeanServer #0 is the Platform MBeanServer, and this class <b>must</b> be
+ used for GlassFish. Additional MBeanServers can be created if desired.
+ <p>
+ This class can also be used to implement an Interceptor which can be set for use by the Primary
+ Interceptor. Such interceptors are used only for get/setAttribute(s) and invoke(), though
+ the use of them could be expanded for other methods.
+ <p>
+ Note that many methods are declared 'final' for efficiency. If a subclass needs
+ to override a method, remove 'final'. Until that time, we might as well remain efficient,
+ since most methods won't be overridden.
+ */
+public class DynamicInterceptor implements MBeanServer
+{
+ private volatile MBeanServer mDelegateMBeanServer;
+ private static final HashMap<String, MBeanServerConnection> instanceConnections =
+ new HashMap<String, MBeanServerConnection>();;
+ private static final LocalStringManagerImpl localStrings =
+ new LocalStringManagerImpl(DynamicInterceptor.class);
+
+ private static final String SERVER_PREFIX = "amx:pp=/domain/servers";
+ private static final String CLUSTER_PREFIX = "amx:pp=/domain/clusters";
+ private static final String CONFIG_PREFIX = "amx:pp=/domain/configs/config[";
+ private static final String JSR77_PREFIX ="amx:pp=/J2EEDomain";
+ private static final String MON_PREFIX ="amx:pp=/mon/server-mon[";
+
+
+ public DynamicInterceptor() {
+ mDelegateMBeanServer = null;
+ // we must initialize this eagely in order to avoid initializing this at the time of shutdown and failing
+ // because the modules have been shutdown. See GLASSFISH-18109 for more details.
+ MbeanService.getInstance();
+ }
+
+ private DynamicInterceptor.ReplicationInfo getTargets( final ObjectName objectName) throws InstanceNotFoundException {
+
+ //TODO : Check if we already have a target list for this ObjectName
+
+ //create a ReplicationInfo instance
+ DynamicInterceptor.ReplicationInfo result = new DynamicInterceptor.ReplicationInfo();
+
+ // if this is for create Mbean
+ if(objectName == null) {
+ result.addInstance("server");
+ return result;
+ }
+
+ String oName = objectName.toString();
+
+ // Initialize the MBeanService and check if we are on DAS
+ if(MbeanService.getInstance() == null) {
+ result.addInstance("server");
+ return result;
+ }
+
+ // Now lets start analysing the Object Name.
+
+ if(objectName.getKeyProperty("type") != null &&
+ (objectName.getKeyProperty("type").equals("Mapper") ||
+ objectName.getKeyProperty("type").equals("Connector") ||
+ objectName.getKeyProperty("type").equals("Engine") ||
+ objectName.getKeyProperty("type").equals("ProtocolHandler") ||
+ objectName.getKeyProperty("type").equals("Service") ||
+ objectName.getKeyProperty("type").equals("Host") ||
+ objectName.getKeyProperty("type").equals("Loader") ||
+ objectName.getKeyProperty("type").equals("JspMonitor") ||
+ objectName.getKeyProperty("type").equals("Valve"))) {
+ result.addInstance("server");
+ return result;
+
+ }
+
+ //If its a MBean corresponding to config
+ if(isConfig(oName)) {
+ String configName = getName(oName);
+ if(configName != null && configName.endsWith("-config")) {
+ String targetName = configName.substring(0, configName.indexOf("-config"));
+ if( (!"default".equals(targetName)) && (!"server".equals(targetName)) ) {
+ result.addAllInstances(MbeanService.getInstance().getInstances(configName));
+ }
+ } else {
+ result.addInstance("server");
+ }
+ }
+
+ // if its a MBean corresponding to a cluster
+ if(isCluster(oName)) {
+ String targetName = getName(oName);
+ if(targetName != null) {
+ result.addAllInstances(MbeanService.getInstance().getInstances(targetName));
+ }
+ }
+
+ // if its an MBean corresponding to a server
+ if(isServer(oName)) {
+ String targetName = getName(oName);
+ if(targetName != null) {
+ result.addInstance(targetName);
+ if(!("server".equals(targetName)))
+ result.setTargetIsAnInstance(true);
+ } else {
+ result.addInstance("server");
+ }
+ }
+
+ // If its an MBean corresponding to a JSR77 managed object
+ if(isJSR77(oName, objectName)) {
+ if(objectName.getKeyProperty("j2eeType") != null &&
+ objectName.getKeyProperty("j2eeType").equals("J2EEDomain")) {
+ result.addInstance("server");
+ } else if (objectName.getKeyProperty("j2eeType") != null &&
+ objectName.getKeyProperty("j2eeType").equals("J2EEServer")) {
+ String targetInstance = objectName.getKeyProperty("name");
+ if(MbeanService.getInstance().isValidServer(targetInstance)) {
+ result.addInstance("server");
+ result.addInstance(targetInstance);
+ }
+ } else {
+ String targetInstance = objectName.getKeyProperty("J2EEServer");
+ if(MbeanService.getInstance().isValidServer(targetInstance)) {
+ result.addInstance(targetInstance);
+ }
+ }
+ }
+
+ // If its an monitoring MBean
+ if(isMonitoring(oName)) {
+ String targetName = getName(oName);
+ result.addInstance(targetName);
+ if(!("server".equals(targetName)))
+ result.setTargetIsAnInstance(true);
+ }
+
+ // If its a generic query
+ if("amx:*".equals(oName) || "*.*".equals(oName)) {
+ result.addInstance("server");
+ result.addAllInstances(MbeanService.getInstance().getAllInstances());
+ }
+
+ if (objectName.getKeyProperty("type")!=null) {
+ if (objectName.getKeyProperty("type").equals("domain-root") ||
+ objectName.getKeyProperty("type").equals("domain") ||
+ objectName.getKeyProperty("type").equals("resources") ||
+ objectName.getKeyProperty("type").equals("system-applications") ||
+ objectName.getKeyProperty("type").equals("applications") ||
+ objectName.getKeyProperty("type").equals("realms") ||
+ objectName.getKeyProperty("type").equalsIgnoreCase("MBeanServerDelegate")) {
+
+ result.addInstance("server");
+ }
+ }
+
+ if( oName.startsWith("amx-support") || oName.startsWith("jmxremote") ) {
+ result.addInstance("server");
+ }
+
+ if((MbeanService.getInstance().isDas())) {
+ result.addInstance("server");
+ return result;
+ }
+ // What abouut JVM
+
+ return result;
+ }
+
+ private DynamicInterceptor.ReplicationInfo getInstance(final ObjectName o) throws InstanceNotFoundException {
+ return getTargets(o);
+ }
+
+ private MBeanServerConnection getInstanceConnection(String instanceName) throws InstanceNotFoundException {
+ // first check if this is on the same instance as the one in the argument
+ // In such a case we delegate to the local MBeanServer
+ if(MbeanService.getInstance().isInstance(instanceName)) {
+ return getDelegateMBeanServer();
+ }
+ // check if this needs a secure connection
+ if(MbeanService.getInstance().isSecureJMX(instanceName)) {
+ return getSecureInstanceConnection(instanceName);
+ }
+ synchronized (instanceConnections) {
+ if (!instanceConnections.containsKey(instanceName)) {
+ try {
+ String urlStr = "service:jmx:rmi:///jndi/rmi://" +
+ MbeanService.getInstance().getHost(instanceName) + ":" +
+ MbeanService.getInstance().getJMXPort(instanceName) + "/jmxrmi";
+ JMXServiceURL url = new JMXServiceURL(urlStr);
+ JMXConnector jmxConn = JMXConnectorFactory.connect(url);
+ MBeanServerConnection conn = jmxConn.getMBeanServerConnection();
+ instanceConnections.put(instanceName, conn);
+ } catch(Exception ex) {
+ throw new InstanceNotFoundException(ex.getLocalizedMessage());
+ }
+ }
+ return instanceConnections.get(instanceName);
+ }
+ }
+
+ private MBeanServerConnection getSecureInstanceConnection(String instanceName) throws InstanceNotFoundException {
+
+ synchronized (instanceConnections) {
+ if (!instanceConnections.containsKey(instanceName)) {
+ try {
+ //
+ System.out.println("\nInitialize the environment map");
+ final Map<String,Object> env = new HashMap<String,Object>();
+ // Provide the SSL/TLS-based RMI Client Socket Factory required
+ // by the JNDI/RMI Registry Service Provider to communicate with
+ // the SSL/TLS-protected RMI Registry
+
+ SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
+ env.put("com.sun.jndi.rmi.factory.socket", csf);
+ String urlStr = "service:jmx:rmi:///jndi/rmi://" +
+ MbeanService.getInstance().getHost(instanceName) + ":" +
+ MbeanService.getInstance().getJMXPort(instanceName) + "/jmxrmi";
+ JMXServiceURL url = new JMXServiceURL(urlStr);
+ JMXConnector jmxConn = JMXConnectorFactory.connect(url, env);
+ MBeanServerConnection conn = jmxConn.getMBeanServerConnection();
+ instanceConnections.put(instanceName, conn);
+ } catch(Exception ex) {
+ throw new InstanceNotFoundException(ex.getLocalizedMessage());
+ }
+ }
+ return instanceConnections.get(instanceName);
+ }
+
+ }
+
+ /**
+ Get the MBeanServer to which the request can be delegated.
+ */
+ public MBeanServer getDelegateMBeanServer() {
+ return mDelegateMBeanServer;
+ }
+
+ public void setDelegateMBeanServer(final MBeanServer server) {
+ mDelegateMBeanServer = server;
+ }
+
+ public Object invoke( final ObjectName objectName, final String operationName,
+ final Object[] params, final String[] signature)
+ throws ReflectionException, InstanceNotFoundException, MBeanException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ Object returnValue = null;
+ try {
+ for(String svr : result.getInstances()) {
+ if("server".equals(svr)) {
+ returnValue = getDelegateMBeanServer().invoke( objectName, operationName, params, signature );
+ } else {
+ returnValue = getInstanceConnection(svr).invoke(objectName, operationName, params, signature);
+ }
+ }
+ } catch (IOException ioex) {
+ throw new ReflectionException(ioex);
+ }
+ return returnValue;
+ }
+
+ public final Object getAttribute(final ObjectName objectName, final String attributeName)
+ throws InstanceNotFoundException, AttributeNotFoundException, MBeanException, ReflectionException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ if(!result.isTargetAnInstance())
+ return getDelegateMBeanServer().getAttribute( objectName, attributeName);
+ try {
+ return getInstanceConnection(result.getInstances().get(0)).getAttribute(objectName, attributeName);
+ } catch (IOException ioex) {
+ throw new ReflectionException(ioex);
+ }
+ }
+
+ public void setAttribute(final ObjectName objectName, final Attribute attribute) throws
+ InstanceNotFoundException, AttributeNotFoundException, MBeanException,
+ ReflectionException, InvalidAttributeValueException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance()) {
+ getInstanceConnection(result.getInstances().get(0)).setAttribute(objectName, attribute);
+ return;
+ }
+ for(String svr : result.getInstances()) {
+ if("server".equals(svr))
+ getDelegateMBeanServer().setAttribute( objectName, attribute );
+ else
+ getInstanceConnection(svr).setAttribute(objectName, attribute);
+ }
+ } catch (IOException ioex) {
+ throw new ReflectionException(ioex);
+ }
+ }
+
+ public final AttributeList getAttributes(final ObjectName objectName, final String[] attrNames)
+ throws InstanceNotFoundException, ReflectionException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance())
+ return getInstanceConnection(result.getInstances().get(0)).getAttributes(objectName, attrNames);
+ else
+ return getDelegateMBeanServer().getAttributes( objectName, attrNames );
+ } catch (IOException ioex) {
+ throw new ReflectionException(ioex);
+ }
+ }
+
+ public AttributeList setAttributes (final ObjectName objectName, final AttributeList attributeList)
+ throws InstanceNotFoundException, ReflectionException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ AttributeList ret = null;
+ try {
+ if(result.isTargetAnInstance())
+ return getInstanceConnection(result.getInstances().get(0)).setAttributes(objectName, attributeList);
+ for(String svr : result.getInstances()) {
+ if((result.getInstances().get(0).equals("server")))
+ ret = getDelegateMBeanServer().setAttributes( objectName, attributeList );
+ else
+ ret = getInstanceConnection(svr).setAttributes(objectName, attributeList);
+ }
+ } catch (IOException ioex) {
+ throw new ReflectionException(ioex);
+ }
+ return ret;
+ }
+
+ public final ObjectInstance registerMBean(final Object obj, final ObjectName objectName)
+ throws NotCompliantMBeanException, MBeanRegistrationException, InstanceAlreadyExistsException {
+ return getDelegateMBeanServer().registerMBean( obj, objectName );
+ }
+
+ public final void unregisterMBean(final ObjectName objectName)
+ throws InstanceNotFoundException, MBeanRegistrationException {
+ // System.out.println("Unregistering MBean :"+objectName.toString());
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance()) {
+ getInstanceConnection(result.getInstances().get(0)).unregisterMBean(objectName);
+ return;
+ }
+ for(String svr : result.getInstances()) {
+ if("server".equals(svr))
+ getDelegateMBeanServer().unregisterMBean( objectName );
+ else
+ getInstanceConnection(svr).unregisterMBean(objectName);
+ }
+ } catch(IOException io) {
+ throw new MBeanRegistrationException(io);
+ }
+ }
+
+ public final Integer getMBeanCount() {
+ return getDelegateMBeanServer().getMBeanCount( );
+ }
+
+ @Override
+ public final Set queryMBeans( final ObjectName objectName, final QueryExp expr ) {
+ //if(objectName == null)
+ // return Collections.EMPTY_SET;
+ try {
+ Set returnVal = null;
+ List<String> instance = getInstance(objectName).getInstances();
+ for(String ins : instance) {
+ Set tmp;
+ if(ins.equals("server"))
+ tmp = getDelegateMBeanServer().queryMBeans(objectName, expr);
+ else
+ tmp = getInstanceConnection(ins).queryMBeans(objectName, expr);
+ if(returnVal == null)
+ returnVal = tmp;
+ else
+ returnVal.addAll(tmp);
+ }
+ return returnVal;
+ } catch (Exception e) {
+ return Collections.EMPTY_SET;
+ }
+ }
+
+ public final MBeanInfo getMBeanInfo( final ObjectName objectName)
+ throws InstanceNotFoundException, IntrospectionException, ReflectionException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance())
+ return getInstanceConnection(result.getInstances().get(0)).getMBeanInfo(objectName);
+ else
+ return getDelegateMBeanServer().getMBeanInfo( objectName );
+ } catch (IOException ioex) {
+ throw new ReflectionException(ioex);
+ }
+ }
+
+ public final boolean isRegistered( final ObjectName objectName) {
+ if(objectName == null)
+ return false;
+ try {
+ List<String> instance = getInstance(objectName).getInstances();
+
+ for(String instanceName : instance) {
+ if(instanceName.equals(System.getProperty("com.sun.aas.instanceName"))) {
+ return getDelegateMBeanServer().isRegistered( objectName );
+ } else {
+ continue;
+ }
+ }
+ return false;
+ /*if((instance.get(0).equals("server")))
+ return getDelegateMBeanServer().isRegistered( objectName );
+ return getInstanceConnection(instance.get(0)).isRegistered(objectName); */
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+
+ public final void addNotificationListener( final ObjectName objectName,
+ final NotificationListener notificationListener,
+ final NotificationFilter notificationFilter, final Object obj)
+ throws InstanceNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance()) {
+ getInstanceConnection(result.getInstances().get(0)).addNotificationListener(
+ objectName, notificationListener, notificationFilter, obj);
+ return;
+ }
+ for(String svr : result.getInstances()) {
+ if("server".equals(svr))
+ getDelegateMBeanServer().addNotificationListener(objectName,
+ notificationListener, notificationFilter, obj);
+ else
+ getInstanceConnection(svr).addNotificationListener(objectName, notificationListener,
+ notificationFilter, obj);
+ }
+ } catch(IOException ioex) {
+ throw new InstanceNotFoundException(ioex.getLocalizedMessage());
+ }
+ }
+
+ public final void addNotificationListener(final ObjectName objectName, final ObjectName objectName1,
+ final NotificationFilter notificationFilter, final Object obj)
+ throws InstanceNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance()) {
+ getInstanceConnection(result.getInstances().get(0)).addNotificationListener(
+ objectName, objectName1, notificationFilter, obj);
+ return;
+ }
+ for(String svr : result.getInstances()) {
+ if("server".equals(svr))
+ getDelegateMBeanServer().addNotificationListener(objectName,
+ objectName1, notificationFilter, obj);
+ else
+ getInstanceConnection(svr).addNotificationListener(objectName, objectName1,
+ notificationFilter, obj);
+ }
+ } catch(IOException ioex) {
+ throw new InstanceNotFoundException(ioex.getLocalizedMessage());
+ }
+ }
+
+ public final ObjectInstance createMBean( final String str, final ObjectName objectName)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException,
+ MBeanException, NotCompliantMBeanException {
+ return createMBean(str, objectName, (Object[]) null, (String[]) null);
+ }
+
+ public final ObjectInstance createMBean( final String str, final ObjectName objectName,
+ final ObjectName objectName2)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException {
+ return createMBean(str, objectName, objectName2, (Object[]) null, (String[]) null);
+ }
+
+ public final ObjectInstance createMBean( final String str, final ObjectName objectName, final Object[] obj,
+ final String[] str3)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException,
+ MBeanException, NotCompliantMBeanException {
+ try {
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ ObjectInstance ret = null;
+ if(result.isTargetAnInstance())
+ return getInstanceConnection(result.getInstances().get(0)).createMBean(str, objectName, obj, str3);
+ for(String svr : result.getInstances())
+ if(svr.equals("server"))
+ ret = getDelegateMBeanServer().createMBean (str, objectName, obj, str3);
+ else
+ ret = getInstanceConnection(svr).createMBean(str, objectName, obj, str3);
+ return ret;
+ } catch (InstanceNotFoundException ex) {
+ throw new MBeanException(ex);
+ } catch (IOException ex) {
+ throw new MBeanException(ex);
+ }
+ }
+
+ public final ObjectInstance createMBean ( final String str, final ObjectName objectName,
+ final ObjectName objectName2, final Object[] obj, final String[] str4)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException,
+ MBeanException, NotCompliantMBeanException, InstanceNotFoundException {
+ try {
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ ObjectInstance ret = null;
+ if(result.isTargetAnInstance())
+ return getInstanceConnection(result.getInstances().get(0)).createMBean(str, objectName,
+ objectName2, obj, str4);
+ for(String svr : result.getInstances())
+ if(svr.equals("server"))
+ ret = getDelegateMBeanServer().createMBean (str, objectName, objectName2, obj, str4);
+ else
+ ret = getInstanceConnection(svr).createMBean(str, objectName, objectName2, obj, str4);
+ return ret;
+ } catch (InstanceNotFoundException ex) {
+ throw new MBeanException(ex);
+ } catch (IOException ex) {
+ throw new MBeanException(ex);
+ }
+ }
+
+ public final ObjectInputStream deserialize (String str, byte[] values)
+ throws OperationsException, ReflectionException {
+ return getDelegateMBeanServer().deserialize (str, values);
+ }
+
+ public final ObjectInputStream deserialize( final ObjectName objectName, final byte[] values)
+ throws InstanceNotFoundException, OperationsException {
+ return getDelegateMBeanServer().deserialize (objectName, values);
+ }
+
+ public final ObjectInputStream deserialize( final String str, final ObjectName objectName, byte[] values)
+ throws InstanceNotFoundException, OperationsException, ReflectionException {
+ return getDelegateMBeanServer().deserialize (str, objectName, values);
+ }
+
+ public final String getDefaultDomain() {
+ return getDelegateMBeanServer().getDefaultDomain();
+ }
+
+ public final ObjectInstance getObjectInstance(ObjectName objectName) throws InstanceNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ List<String> instance = getInstance(objectName).getInstances();
+ if(instance.size() != 1)
+ throw new InstanceNotFoundException(localStrings.getLocalString("interceptor.objectName.wrongservernames",
+ "This mbean call does not support multiple target instances"));
+ if((instance.get(0).equals("server")))
+ return getDelegateMBeanServer().getObjectInstance(objectName);
+ try {
+ return getInstanceConnection(instance.get(0)).getObjectInstance(objectName);
+ } catch (IOException ioex) {
+ throw new InstanceNotFoundException(ioex.getLocalizedMessage());
+ }
+ }
+
+ public final Object instantiate( final String str) throws ReflectionException, MBeanException {
+ return getDelegateMBeanServer().instantiate(str);
+ }
+
+ public final Object instantiate( final String str, final ObjectName objectName)
+ throws ReflectionException, MBeanException, InstanceNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ return getDelegateMBeanServer().instantiate(str, objectName);
+ }
+
+ public final Object instantiate( final String str, final Object[] obj, final String[] str2)
+ throws ReflectionException, MBeanException {
+ return getDelegateMBeanServer().instantiate(str, obj, str2);
+ }
+
+ public final Object instantiate( final String str, final ObjectName objectName, final Object[] obj,
+ final String[] str3)
+ throws ReflectionException, MBeanException, InstanceNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ return getDelegateMBeanServer().instantiate(str, objectName, obj, str3);
+ }
+
+ public final boolean isInstanceOf ( final ObjectName objectName, final String str)
+ throws InstanceNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ List<String> instance = getInstance(objectName).getInstances();
+ if(instance.size() != 1)
+ throw new InstanceNotFoundException(localStrings.getLocalString("interceptor.objectName.wrongservernames",
+ "This mbean call does not support multiple target instances"));
+ if((instance.get(0).equals("server")))
+ return getDelegateMBeanServer().isInstanceOf(objectName, str);
+ try {
+ return getInstanceConnection(instance.get(0)).isInstanceOf(objectName, str);
+ } catch (IOException ioex) {
+ throw new InstanceNotFoundException(ioex.getLocalizedMessage());
+ }
+ }
+
+ public final Set queryNames( final ObjectName objectName, final QueryExp queryExp) {
+ Set returnVal = null;
+ //if(objectName == null)
+ //return Collections.EMPTY_SET;
+ List<String> instance;
+ try {
+ instance = getInstance(objectName).getInstances();
+ } catch(InstanceNotFoundException e) {
+ return Collections.EMPTY_SET;
+ }
+ for(String ins : instance) {
+ Set tmp = null;
+ if(ins.equals("server")) {
+ tmp = getDelegateMBeanServer().queryNames( objectName, queryExp);
+ } else {
+ try {
+ tmp = getInstanceConnection(ins).queryNames(objectName, queryExp);
+ } catch(Exception e) {
+ //Swallowing this intentionally
+ //Because this can happen only if the instance is down / not responding
+ }
+ }
+ if(tmp != null) {
+ if(returnVal == null)
+ returnVal = tmp;
+ else
+ returnVal.addAll(tmp);
+ }
+ }
+ if(returnVal == null)
+ return Collections.EMPTY_SET;
+ return returnVal;
+ }
+
+ public final void removeNotificationListener(final ObjectName objectName, final ObjectName objectName1)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance()) {
+ getInstanceConnection(result.getInstances().get(0)).removeNotificationListener(objectName, objectName1);
+ return;
+ }
+ for(String svr : result.getInstances()) {
+ if(svr.equals("server"))
+ getDelegateMBeanServer().removeNotificationListener( objectName, objectName1);
+ else
+ getInstanceConnection(svr).removeNotificationListener(objectName, objectName1);
+ }
+ } catch (IOException ioex) {
+ throw new InstanceNotFoundException(ioex.getLocalizedMessage());
+ }
+ }
+
+ public final void removeNotificationListener( final ObjectName objectName,
+ final NotificationListener notificationListener)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance()) {
+ getInstanceConnection(result.getInstances().get(0)).removeNotificationListener(objectName, notificationListener);
+ return;
+ }
+ for(String svr : result.getInstances()) {
+ if(svr.equals("server"))
+ getDelegateMBeanServer().removeNotificationListener( objectName, notificationListener);
+ else
+ getInstanceConnection(svr).removeNotificationListener(objectName, notificationListener);
+ }
+ } catch (IOException ioex) {
+ throw new InstanceNotFoundException(ioex.getLocalizedMessage());
+ }
+ }
+
+ public final void removeNotificationListener( final ObjectName objectName,
+ final NotificationListener notificationListener,
+ final NotificationFilter notificationFilter, final Object obj)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance()) {
+ getInstanceConnection(result.getInstances().get(0)).removeNotificationListener(objectName,
+ notificationListener, notificationFilter, obj);
+ return;
+ }
+ for(String svr : result.getInstances()) {
+ if(svr.equals("server"))
+ getDelegateMBeanServer().removeNotificationListener( objectName,
+ notificationListener,notificationFilter, obj);
+ else
+ getInstanceConnection(svr).removeNotificationListener(objectName,
+ notificationListener, notificationFilter, obj);
+ }
+ } catch (IOException ioex) {
+ throw new InstanceNotFoundException(ioex.getLocalizedMessage());
+ }
+ }
+
+ public final void removeNotificationListener( final ObjectName objectName, final ObjectName objectName1,
+ final NotificationFilter notificationFilter, final Object obj)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ DynamicInterceptor.ReplicationInfo result = getInstance(objectName);
+ try {
+ if(result.isTargetAnInstance()) {
+ getInstanceConnection(result.getInstances().get(0)).removeNotificationListener(objectName,
+ objectName1, notificationFilter, obj);
+ return;
+ }
+ for(String svr : result.getInstances()) {
+ if(svr.equals("server"))
+ getDelegateMBeanServer().removeNotificationListener( objectName,
+ objectName1,notificationFilter, obj);
+ else
+ getInstanceConnection(svr).removeNotificationListener(objectName,
+ objectName1, notificationFilter, obj);
+ }
+ } catch (IOException ioex) {
+ throw new InstanceNotFoundException(ioex.getLocalizedMessage());
+ } }
+
+ public final ClassLoader getClassLoader( final ObjectName objectName) throws InstanceNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ return getDelegateMBeanServer().getClassLoader( objectName );
+ }
+
+ public final ClassLoader getClassLoaderFor( final ObjectName objectName) throws InstanceNotFoundException {
+ if(objectName == null)
+ throw new InstanceNotFoundException();
+ return getDelegateMBeanServer().getClassLoaderFor( objectName );
+ }
+
+ public final ClassLoaderRepository getClassLoaderRepository() {
+ return getDelegateMBeanServer().getClassLoaderRepository();
+ }
+
+ public final String[] getDomains() {
+ return getDelegateMBeanServer().getDomains();
+ }
+
+ private boolean isConfig(String oName) {
+ return oName.startsWith(CONFIG_PREFIX);
+ }
+
+ private boolean isCluster(String oName) {
+ return oName.startsWith(CLUSTER_PREFIX);
+ }
+
+ private boolean isServer(String oName) {
+ return oName.startsWith(SERVER_PREFIX);
+ }
+
+ private boolean isJSR77(String oName, ObjectName o) {
+ if(o.getKeyProperty("j2eeType") !=null) {
+ return true;
+ } else if(oName.startsWith(JSR77_PREFIX)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean isMonitoring(String oName) {
+ return oName.startsWith(MON_PREFIX);
+ }
+
+ private String getName(String oName) {
+ if(oName.indexOf("[") != -1 ) {
+ return oName.substring(oName.indexOf("[") + 1, oName.indexOf("]"));
+ } else {
+ return null;
+ }
+ }
+
+ private static class ReplicationInfo {
+ private boolean instanceTarget = false;
+ private List<String> instances = new ArrayList<String>();
+
+ boolean isTargetAnInstance() { return instanceTarget;}
+
+ void setTargetIsAnInstance(boolean b) { instanceTarget = b;}
+
+ List<String> getInstances() { return instances;}
+
+ void addInstance(String s) {
+ if(!instances.contains(s)) {
+ instances.add(s);
+ }
+ }
+
+ void addAllInstances(List list) {
+ instances.addAll(list);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/GetCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/GetCommand.java
new file mode 100644
index 0000000..d7407f3
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/GetCommand.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import java.util.*;
+import java.util.logging.Logger;
+
+import com.sun.enterprise.config.modularity.ConfigModularityUtils;
+import com.sun.enterprise.config.modularity.GetSetModularityHelper;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.v3.common.PropsFileActionReporter;
+import java.util.logging.Level;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import org.glassfish.flashlight.MonitoringRuntimeDataRegistry;
+import org.glassfish.internal.api.Target;
+import javax.inject.Inject;
+import org.glassfish.api.admin.AccessRequired.AccessCheck;
+
+import org.jvnet.hk2.annotations.Optional;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.Dom;
+import org.jvnet.hk2.config.types.Property;
+
+
+/**
+ * User: Jerome Dochez
+ * Date: Jul 10, 2008
+ * Time: 12:17:26 AM
+ */
+@Service(name = "get")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="get",
+ description="Get")
+})
+public class GetCommand extends V2DottedNameSupport implements AdminCommand,
+ AdminCommandSecurity.Preauthorization,
+ AdminCommandSecurity.AccessCheckProvider {
+ @Inject
+ private MonitoringReporter mr;
+ @Inject
+ private Domain domain;
+ @Inject
+ private ServerEnvironment serverEnv;
+ @Inject
+ private Target targetService;
+ @Inject
+ private ServiceLocator habitat;
+ @Param(optional = true, defaultValue = "false", shortName = "m")
+ private Boolean monitor;
+ @Param(optional = true, defaultValue = "false", shortName = "c")
+ private Boolean aggregateDataOnly;
+ @Param(primary = true)
+ private String pattern;
+ @Inject @Optional
+ private MonitoringRuntimeDataRegistry mrdr;
+ final private static LocalStringManagerImpl localStrings =
+ new LocalStringManagerImpl(GetCommand.class);
+
+ private ActionReport report;
+
+ private List<Map.Entry> matchingNodesSorted;
+
+ private String prefix;
+
+ @Inject
+ @Optional
+ GetSetModularityHelper modularityHelper;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ if (monitor) {
+ return preAuthorizationForMonitoring(context);
+ } else {
+ return preAuthorizationForNonMonitoring(context);
+ }
+ }
+
+ private boolean preAuthorizationForMonitoring(final AdminCommandContext context) {
+ mr.prepareGet(context, pattern, aggregateDataOnly);
+ return true;
+ }
+
+ private boolean preAuthorizationForNonMonitoring(final AdminCommandContext context) {
+ report = context.getActionReport();
+
+ /* Issue 5918 Used in ManifestManager to keep output sorted */
+ try {
+ PropsFileActionReporter reporter = (PropsFileActionReporter) report;
+ reporter.useMainChildrenAttribute(true);
+ }
+ catch (ClassCastException e) {
+ // ignore this is not a manifest output.
+ }
+
+ matchingNodesSorted = findSortedMatchingNodes();
+ return matchingNodesSorted != null;
+ }
+
+ @Override
+ public Collection<? extends AccessCheck> getAccessChecks() {
+ if (monitor) {
+ return mr.getAccessChecksForGet();
+ } else {
+ return getAccessChecksForNonMonitoring();
+ }
+ }
+
+ private Collection<? extends AccessCheck> getAccessChecksForNonMonitoring() {
+ final Collection<AccessCheck> accessChecks = new ArrayList<AccessCheck>();
+ for (Map.Entry entry : matchingNodesSorted) {
+ accessChecks.add(new AccessCheck(AccessRequired.Util.resourceNameFromDom((Dom)entry.getKey()), "read"));
+ }
+ return accessChecks;
+ }
+
+ @Override
+ public void execute(AdminCommandContext context) {
+
+ if (monitor) {
+ getMonitorAttributes(context);
+ //String old = report.getMessage();
+ //String append = "\nXXXXXXXXX\n" + mr.toString();
+ //report.setMessage(old == null ? append : old + append);
+ return;
+ }
+
+
+ boolean foundMatch = false;
+ for (Map.Entry<Dom, String> node : matchingNodesSorted) {
+ // if we get more of these special cases, we should switch to a Renderer pattern
+ if (Property.class.getName().equals(node.getKey().model.targetTypeName)) {
+ // special display for properties...
+ if (matches(node.getValue(), pattern)) {
+ ActionReport.MessagePart part = report.getTopMessagePart().addChild();
+ part.setChildrenType("DottedName");
+ part.setMessage(prefix + node.getValue() + "=" + node.getKey().attribute("value"));
+ foundMatch = true;
+ }
+ }
+ else {
+ Map<String, String> attributes = getNodeAttributes(node.getKey(), pattern);
+ TreeMap<String, String> attributesSorted = new TreeMap(attributes);
+ for (Map.Entry<String, String> name : attributesSorted.entrySet()) {
+ String finalDottedName = node.getValue() + "." + name.getKey();
+ if (matches(finalDottedName, pattern)) {
+ ActionReport.MessagePart part = report.getTopMessagePart().addChild();
+ part.setChildrenType("DottedName");
+ part.setMessage(prefix + node.getValue() + "." + name.getKey() + "=" + name.getValue());
+ foundMatch = true;
+ }
+ }
+ }
+ }
+ if (!foundMatch) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ //report.setMessage("No object found matching " + pattern);
+ report.setMessage(localStrings.getLocalString("admin.get.path.notfound", "Dotted name path {0} not found.", prefix + pattern));
+
+ }
+ }
+
+ private void getMonitorAttributes(AdminCommandContext ctxt) {
+
+ Logger l = KernelLoggerInfo.getLogger();
+ if (l.isLoggable(Level.FINE)) {
+ l.log(Level.FINE, "Get Command: {0}", mr.toString());
+ }
+ mr.execute();
+ }
+
+ private List<Map.Entry> findSortedMatchingNodes() {
+
+ if (!monitor) {
+ if (modularityHelper != null) {
+ modularityHelper.getLocationForDottedName(pattern);
+ }
+ }
+ // check for logging patterns
+ if (pattern.contains(".log-service")) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(localStrings.getLocalString("admin.get.invalid.logservice.command", "For getting log levels/attributes use list-log-levels/list-log-attributes command."));
+ return null;
+ }
+
+ //check for incomplete dotted name
+ if (!pattern.equals("*")) {
+ if (pattern.lastIndexOf(".") == -1 || pattern.lastIndexOf(".") == (pattern.length() - 1)) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ //report.setMessage("Missing expected dotted name part");
+ report.setMessage(localStrings.getLocalString("missing.dotted.name", "Missing expected dotted name part"));
+ return null;
+ }
+ }
+
+ // first let's get the parent for this pattern.
+ TreeNode[] parentNodes = getAliasedParent(domain, pattern);
+
+ // reset the pattern.
+ prefix = "";
+ if(!pattern.startsWith(parentNodes[0].relativeName)) {
+ prefix = pattern.substring(0, pattern.indexOf(parentNodes[0].relativeName));
+ pattern = parentNodes[0].relativeName;
+ } else {
+ pattern = parentNodes[0].relativeName;
+ }
+
+ Map<Dom, String> matchingNodes;
+ Map<Dom, String> dottedNames = new HashMap<Dom, String>();
+ for (TreeNode parentNode : parentNodes) {
+ dottedNames.putAll(getAllDottedNodes(parentNode.node));
+ if (parentNode.name.equals("")) {
+ dottedNames.put(parentNode.node, "domain");
+ }
+ }
+ matchingNodes = getMatchingNodes(dottedNames, pattern);
+ if (matchingNodes.isEmpty() && pattern.lastIndexOf('.') != -1) {
+ // it's possible the user is just looking for an attribute, let's remove the
+ // last element from the pattern.
+ matchingNodes = getMatchingNodes(dottedNames, pattern.substring(0, pattern.lastIndexOf(".")));
+ }
+
+ //No matches found - report the failure and return
+ if (matchingNodes.isEmpty()) {
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ //report.setMessage("Dotted name path \"" + prefix + pattern + "\" not found.");
+ report.setMessage(localStrings.getLocalString("admin.get.path.notfound", "Dotted name path {0} not found.", prefix + pattern));
+ return null;
+ }
+
+ List<Map.Entry> result = sortNodesByDottedName(matchingNodes);
+ result = applyOverrideRules(result);
+ return result;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/GetHabitatInfo.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/GetHabitatInfo.java
new file mode 100644
index 0000000..d94bdf3
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/GetHabitatInfo.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.inject.Inject;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.Payload;
+import javax.validation.constraints.Pattern;
+
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.ActionReport.ExitCode;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.RestEndpoint;
+import org.glassfish.api.admin.RestEndpoints;
+import org.glassfish.hk2.api.ActiveDescriptor;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceHandle;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.jvnet.hk2.annotations.Service;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.customvalidators.JavaClassName;
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.universal.collections.ManifestUtils;
+import com.sun.enterprise.v3.common.PropsFileActionReporter;
+import org.glassfish.api.admin.AccessRequired;
+
+/**
+ * Dumps a sorted list of all registered Contract's in the Habitat
+ *
+ * <p>
+ * Useful for debugging and developing new Contract's
+ * @author Byron Nevins
+ * @param <i>
+ */
+@Service(name = "_get-habitat-info")
+@PerLookup
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="_get-habitat-info",
+ description="_get-habitat-info")
+})
+@GetHabitatInfo.Constraint
+@AccessRequired(resource="domain", action="dump")
+public class GetHabitatInfo implements AdminCommand {
+ @Inject
+ ServiceLocator serviceLocator;
+
+ @Inject
+ ModulesRegistry modulesRegistry;
+
+ @JavaClassName
+ @Param(primary = true, optional = true)
+ String contract;
+
+ @Pattern(regexp="true|false")
+ @Param(optional = true)
+ String started = "false";
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ StringBuilder sb = new StringBuilder();
+ if (contract == null) {
+ dumpContracts(sb);
+ dumpModules(sb);
+ dumpTypes(sb);
+ }
+ else {
+ dumpInhabitantsImplementingContractPattern(contract, sb);
+ }
+
+
+ String msg = sb.toString();
+ ActionReport report = context.getActionReport();
+ report.setActionExitCode(ExitCode.SUCCESS);
+
+ if (report instanceof PropsFileActionReporter) {
+ msg = ManifestUtils.encode(msg);
+ }
+ report.setMessage(msg);
+ }
+
+ private void dumpContracts(StringBuilder sb) {
+ // Probably not very efficient but it is not a factor for this rarely-used
+ // user-called command...
+
+ sb.append("\n*********** Sorted List of all Registered Contracts in the Habitat **************\n");
+ List<ActiveDescriptor<?>> allDescriptors = serviceLocator.getDescriptors(BuilderHelper.allFilter());
+
+ SortedSet<String> allContracts = new TreeSet<String>();
+ for (ActiveDescriptor<?> aDescriptor : allDescriptors) {
+ allContracts.addAll(aDescriptor.getAdvertisedContracts());
+ }
+
+ // now the contracts are sorted...
+
+ Iterator<String> it = allContracts.iterator();
+ for (int i = 1; it.hasNext(); i++) {
+ sb.append("Contract-" + i + ": " + it.next() + "\n");
+ }
+ }
+
+ private void dumpInhabitantsImplementingContractPattern(String pattern, StringBuilder sb) {
+ sb.append("\n*********** List of all services for contract named like " + contract + " **************\n");
+ List<ActiveDescriptor<?>> allDescriptors = serviceLocator.getDescriptors(BuilderHelper.allFilter());
+ HashSet<String> allContracts = new HashSet<String>();
+ for (ActiveDescriptor<?> aDescriptor : allDescriptors) {
+ allContracts.addAll(aDescriptor.getAdvertisedContracts());
+ }
+
+ Iterator<String> it = allContracts.iterator();
+ while (it.hasNext()) {
+ String cn = it.next();
+ if (cn.toLowerCase(Locale.ENGLISH).indexOf(pattern.toLowerCase(Locale.ENGLISH)) < 0)
+ continue;
+ sb.append("\n-----------------------------\n");
+ for ( ActiveDescriptor<?> descriptor : serviceLocator.getDescriptors(BuilderHelper.createContractFilter(cn))) {
+ sb.append("Inhabitant-Metadata: " + descriptor.getMetadata());
+ sb.append("\n");
+ boolean isStarted = Boolean.parseBoolean(started);
+ if (isStarted) {
+ ServiceHandle<?> handle = serviceLocator.getServiceHandle(descriptor);
+
+ sb.append((handle.isActive() ? " started" : " not started"));
+ }
+ }
+ }
+ }
+
+ private void dumpTypes(StringBuilder sb) {
+ sb.append("\n\n*********** Sorted List of all Types in the Habitat **************\n\n");
+ List<ActiveDescriptor<?>> allDescriptors = serviceLocator.getDescriptors(BuilderHelper.allFilter());
+ HashSet<String> allTypes = new HashSet<String>();
+ for (ActiveDescriptor<?> aDescriptor : allDescriptors) {
+ allTypes.add(aDescriptor.getImplementation());
+ }
+
+ Iterator<String> it = allTypes.iterator();
+
+ if (it == null) //PP (paranoid programmer)
+ return;
+
+ SortedSet<String> types = new TreeSet<String>();
+
+ while (it.hasNext()) {
+ types.add(it.next());
+ }
+
+ // now the types are sorted...
+
+ it = types.iterator();
+
+ for (int i = 1; it.hasNext(); i++) {
+ sb.append("Type-" + i + ": " + it.next() + "\n");
+ }
+ }
+
+ private void dumpModules(StringBuilder sb) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ modulesRegistry.dumpState(new PrintStream(baos));
+ sb.append("\n\n*********** List of all Registered Modules **************\n\n");
+ sb.append(baos.toString());
+ }
+ /*
+ * NOTE: this valdation is here just to test the AdminCommand validation
+ * implementation.
+ */
+ @Retention(RUNTIME)
+ @Target({TYPE})
+ @javax.validation.Constraint(validatedBy = GetHabitatInfo.Validator.class)
+ public static @interface Constraint {
+ String message() default "The contract argument is test but started is true.";
+ Class<?>[] groups() default {};
+ Class<? extends Payload>[] payload() default {};
+ }
+
+ public static class Validator
+ implements ConstraintValidator<GetHabitatInfo.Constraint, GetHabitatInfo>, Payload {
+
+ @Override
+ public void initialize(final GetHabitatInfo.Constraint constraint) { }
+
+ @Override
+ public boolean isValid(final GetHabitatInfo bean,
+ final ConstraintValidatorContext constraintValidatorContext) {
+ if (bean.contract.equals("test") && bean.started.equals("true"))
+ return false;
+ return true;
+ }
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/GetRestartRequiredCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/GetRestartRequiredCommand.java
new file mode 100644
index 0000000..bd2a830
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/GetRestartRequiredCommand.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandLock;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.config.UnprocessedChangeEvent;
+import org.jvnet.hk2.config.UnprocessedChangeEvents;
+import org.glassfish.internal.config.UnprocessedConfigListener;
+
+/**
+ * Return the "restart required" flag.
+ *
+ * @author Bill Shannon
+ */
+@Service(name = "_get-restart-required")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("get.restart.required.command")
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="_get-restart-required",
+ description="Restart Reasons")
+})
+@AccessRequired(resource="domain", action="dump")
+public class GetRestartRequiredCommand implements AdminCommand {
+ @Param(optional = true)
+ private boolean why;
+
+ @Inject
+ private UnprocessedConfigListener ucl;
+
+ public void execute(AdminCommandContext context) {
+ ActionReport report = context.getActionReport();
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ ActionReport.MessagePart mp = report.getTopMessagePart();
+
+ Properties extraProperties = new Properties();
+ Map<String, Object> entity = new HashMap<String, Object>();
+ mp.setMessage(Boolean.toString(ucl.serverRequiresRestart()));
+ entity.put("restartRequired", Boolean.toString(ucl.serverRequiresRestart()));
+ List<String> unprocessedChanges = new ArrayList<String>();
+
+ for (UnprocessedChangeEvents es : ucl.getUnprocessedChangeEvents()) {
+ for (UnprocessedChangeEvent e : es.getUnprocessed()) {
+ if (why) {
+ mp.addChild().setMessage(e.getReason());
+ }
+ unprocessedChanges.add(e.getReason());
+ }
+ }
+
+ if (!unprocessedChanges.isEmpty()) {
+ entity.put("unprocessedChanges", unprocessedChanges);
+ }
+ extraProperties.put("entity", entity);
+ ((ActionReport) report).setExtraProperties(extraProperties);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/IdmService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/IdmService.java
new file mode 100644
index 0000000..8efadc8
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/IdmService.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.glassfish.bootstrap.StartupContextUtil;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.security.store.IdentityManagement;
+import com.sun.enterprise.security.store.PasswordAdapter;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.internal.api.InitRunLevel;
+import org.glassfish.security.common.MasterPassword;
+import org.glassfish.server.ServerEnvironmentImpl;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jvnet.hk2.annotations.Optional;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PostConstruct;
+import javax.inject.Singleton;
+
+import java.io.*;
+import java.util.Arrays;
+import java.util.Properties;
+import java.util.logging.Logger;
+import org.glassfish.api.admin.PasswordAliasStore;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.glassfish.security.services.impl.JCEKSPasswordAliasStore;
+
+/** An implementation of the @link {IdentityManagement} that manages the password needs of the server.
+ * This implementation consults the Java KeyStore and assumes that the stores are available in server's
+ * configuration area.
+ * @author केदार (km@dev.java.net)
+ */
+@Service(name="jks-based")
+public class IdmService implements PostConstruct, IdentityManagement {
+
+ private final Logger logger = Logger.getAnonymousLogger();
+
+ @Inject
+ private volatile StartupContext sc = null;
+
+ @Inject
+ private volatile ServerEnvironmentImpl env = null;
+
+ private char[] masterPassword;
+
+ private static final String FIXED_KEY = "master-password"; //the fixed key for master-password file
+ private static final String PASSWORDFILE_OPTION_TO_ASMAIN = "-passwordfile"; //note single hyphen, in line with other args to ASMain!
+ private static final String STDIN_OPTION_TO_ASMAIN = "-read-stdin"; //note single hyphen, in line with other args to ASMain!
+
+ private static final String MP_PROPERTY = "AS_ADMIN_MASTERPASSWORD";
+
+ public void postConstruct() {
+ boolean success;
+ boolean readStdin = sc.getArguments().containsKey(STDIN_OPTION_TO_ASMAIN);
+ if (readStdin) {
+ success = setFromStdin();
+ } else {
+ success = setFromMasterPasswordFile();
+ if (!success) {
+ success = setFromAsMainArguments();
+ }
+ }
+ if (!success) {
+ masterPassword = "changeit".toCharArray(); //the default;
+ }
+ }
+
+ @Override
+ public char[] getMasterPassword() {
+ return Arrays.copyOf(masterPassword, masterPassword.length);
+ }
+
+ ///// All Private
+
+ private boolean setFromMasterPasswordFile() {
+ try {
+ File mp = env.getMasterPasswordFile();
+ if (!mp.isFile()) {
+ logger.fine("The JCEKS file: " + mp.getAbsolutePath() + " does not exist, master password was not saved on disk during domain creation");
+ return false;
+ }
+ final PasswordAliasStore masterPasswordAliasStore = JCEKSPasswordAliasStore.newInstance(mp.getAbsolutePath(), FIXED_KEY.toCharArray());
+ char[] mpChars = masterPasswordAliasStore.get(FIXED_KEY);
+ if (mpChars == null) {
+ return false;
+ }
+ masterPassword = mpChars;
+ return true;
+ } catch (Exception ex) {
+ logger.fine("Error in master-password processing: " + ex.getMessage());
+ return false;
+ }
+
+ }
+
+ private boolean setFromAsMainArguments() {
+ File pwf = null;
+ try {
+ String[] args = StartupContextUtil.getOriginalArguments(sc);
+ int index = 0;
+ for (String arg : args) {
+ if (PASSWORDFILE_OPTION_TO_ASMAIN.equals(arg)) {
+ if (index == (args.length-1)) { //-passwordfile is the last argument
+ logger.warning(KernelLoggerInfo.optionButNoArg);
+ return false;
+ }
+ pwf = new File(args[index+1]);
+ return readPasswordFile(pwf);
+ }
+ index++;
+ }
+ //no -passwordfile found
+ return false;
+ } catch (Exception ex) {
+ String s = "Something wrong with given password file: ";
+ String msg = pwf == null ? s : s + pwf.getAbsolutePath();
+ logger.fine(msg);
+ return false;
+ }
+ }
+
+ private boolean readPasswordFile(File pwf) {
+ Properties p = new Properties();
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new FileReader(pwf));
+ p.load(br);
+ if (p.getProperty(MP_PROPERTY) == null)
+ return false;
+ masterPassword = p.getProperty(MP_PROPERTY).toCharArray(); //this would stay in memory, so this needs some security audit, frankly
+ return true;
+ } catch (IOException e) {
+ logger.fine("Passwordfile: " + pwf.getAbsolutePath() + " (a simple property file) could not be processed, ignoring ...");
+ return false;
+ } finally {
+ try {
+ if (br != null)
+ br.close();
+ } catch(Exception e) {
+ // ignore, I know
+ }
+ }
+ }
+
+ private boolean setFromStdin() {
+ logger.fine("Reading the master password from stdin> ");
+ String s;
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ while ((s = br.readLine()) != null) {
+ int ind = s.indexOf(MP_PROPERTY);
+ if (ind == -1) {
+ return false; // this means stdin isn't behaving. That's bad and shouldn't happen.
+ }
+ masterPassword = s.substring(MP_PROPERTY.length() + 1).toCharArray(); //begIndex is that of "AS_ADMIN_MASTERPASSWORD=; consider trailing '='
+ }
+ // We don't want reveal the master password in the logs.
+ //logger.fine("******************* Password from stdin: " + new String(masterPassword));
+ if (masterPassword == null) {
+ return false;
+ }
+ return true;
+ } catch(Exception e) {
+ logger.fine("Stdin isn't behaving, ignoring it ..." + e.getMessage());
+ return false;
+ }
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/InserverCommandRunnerHelper.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/InserverCommandRunnerHelper.java
new file mode 100644
index 0000000..4c6bddf
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/InserverCommandRunnerHelper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.security.auth.Subject;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.CommandRunner;
+import org.glassfish.api.admin.ParameterMap;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ *
+ * Allows commands executing in the DAS or an instance to invoke other
+ * commands in the same server. This will be most useful from commands
+ * that need to change configuration settings by delegating to a
+ * sequence of other commands.
+ * <p>
+ * This is similar to some logic in the AdminAdapter.
+ *
+ * @author Tim Quinn
+ *
+ */
+@Service
+@Singleton
+public class InserverCommandRunnerHelper {
+
+ public final static Logger logger = KernelLoggerInfo.getLogger();
+ public final static LocalStringManagerImpl adminStrings = new LocalStringManagerImpl(InserverCommandRunnerHelper.class);
+
+ @Inject
+ private CommandRunnerImpl commandRunner;
+
+ public ActionReport runCommand(final String command,
+ final ParameterMap parameters,
+ final ActionReport report,
+ final Subject subject) {
+ try {
+ final AdminCommand adminCommand = commandRunner.getCommand(command, report, logger);
+ if (adminCommand==null) {
+ // maybe commandRunner already reported the failure?
+ if (report.getActionExitCode() == ActionReport.ExitCode.FAILURE)
+ return report;
+ String message =
+ adminStrings.getLocalString("adapter.command.notfound",
+ "Command {0} not found", command);
+ // cound't find command, not a big deal
+ logger.log(Level.FINE, message);
+ report.setMessage(message);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return report;
+ }
+ CommandRunner.CommandInvocation inv = commandRunner.getCommandInvocation(command, report, subject);
+ inv.parameters(parameters).execute();
+ } catch (Throwable t) {
+ /*
+ * Must put the error information into the report
+ * for the client to see it.
+ */
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(t);
+ report.setMessage(t.getLocalizedMessage());
+ report.setActionDescription("Last-chance exception handler");
+ }
+ return report;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobAuthorizationAttributeProcessor.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobAuthorizationAttributeProcessor.java
new file mode 100644
index 0000000..2176736
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobAuthorizationAttributeProcessor.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.security.auth.Subject;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AuthorizationPreprocessor;
+import org.glassfish.api.admin.Job;
+import org.glassfish.api.admin.progress.JobInfo;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Attaches a user attribute to job resources for authorization.
+ *
+ * @author Tim Quinn
+ * @author Bhakti Mehta
+ */
+@Service
+@Singleton
+public class JobAuthorizationAttributeProcessor implements AuthorizationPreprocessor {
+
+ private final static String USER_ATTRIBUTE_NAME = "user";
+
+ public final static String JOB_RESOURCE_NAME_PREFIX_NO_SLASH = "jobs/job";
+ public final static String JOB_RESOURCE_NAME_PREFIX = JOB_RESOURCE_NAME_PREFIX_NO_SLASH + '/';
+
+ public final static Pattern JOB_PATTERN = Pattern.compile("(?:" + JOB_RESOURCE_NAME_PREFIX_NO_SLASH + "(?:/(\\d*))?)");
+
+ @Inject
+ private JobManagerService jobManager;
+
+ @Override
+ public void describeAuthorization(Subject subject, String resourceName, String action, AdminCommand command, Map<String, Object> context, Map<String, String> subjectAttributes, Map<String, String> resourceAttributes, Map<String, String> actionAttributes) {
+ final Matcher m = JOB_PATTERN.matcher(resourceName);
+ if ( ! m.matches()) {
+ return;
+ }
+ if (m.groupCount() == 0) {
+ /*
+ * The resource name pattern did not match for including a job ID,
+ * so we will not be able to attach a user attribute to the resource.
+ */
+ return;
+ }
+ final String jobID = m.group(1);
+ final Job job = jobManager.get(jobID);
+ String userID = null;
+
+ /*
+ * This logic might run before any validation in the command has run,
+ * in which case the job ID would be invalid and the job manager and/or
+ * the completed jobs store might not know about the job.
+ */
+ if (job != null && job.getSubjectUsernames().size() > 0) {
+ userID = job.getSubjectUsernames().get(0);
+ } else {
+ if (jobManager.getCompletedJobs(jobManager.getJobsFile()) != null) {
+ final JobInfo jobInfo = (JobInfo) jobManager.getCompletedJobForId(jobID);
+ if (jobInfo != null) {
+ userID = jobInfo.user;
+ }
+ }
+ }
+
+ if (userID != null) {
+ resourceAttributes.put(USER_ATTRIBUTE_NAME, userID);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobCleanUpService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobCleanUpService.java
new file mode 100644
index 0000000..3307e5e
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobCleanUpService.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.ManagedJobConfig;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import org.glassfish.api.StartupRunLevel;
+import org.glassfish.api.admin.progress.JobInfo;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.Changed;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.ConfigListener;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.NotProcessed;
+import org.jvnet.hk2.config.ObservableBean;
+import org.jvnet.hk2.config.UnprocessedChangeEvents;
+
+import javax.inject.Inject;
+import java.beans.PropertyChangeEvent;
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * This is an hk2 service which will clear all expired and inactive jobs
+ * @author Bhakti Mehta
+ */
+@Service(name="job-cleanup")
+@RunLevel(value= StartupRunLevel.VAL)
+public class JobCleanUpService implements PostConstruct,ConfigListener {
+
+ @Inject
+ JobManagerService jobManagerService;
+
+ @Inject
+ Domain domain;
+
+ private ManagedJobConfig managedJobConfig;
+
+ private final static Logger logger = KernelLoggerInfo.getLogger();
+
+ private ScheduledExecutorService scheduler;
+
+
+ private static final LocalStringManagerImpl adminStrings =
+ new LocalStringManagerImpl(JobCleanUpService.class);
+
+
+
+ @Override
+ public void postConstruct() {
+ logger.log(Level.FINE,KernelLoggerInfo.initializingJobCleanup);
+
+ managedJobConfig = domain.getExtensionByType(ManagedJobConfig.class);
+ ObservableBean bean = (ObservableBean) ConfigSupport.getImpl(managedJobConfig);
+ logger.fine(KernelLoggerInfo.initializingManagedConfigBean);
+ bean.addListener(this);
+
+
+ scheduler = Executors.newScheduledThreadPool(10, new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread result = new Thread(r);
+ result.setDaemon(true);
+ return result;
+ }
+ });
+
+
+ scheduleCleanUp();
+ }
+
+
+ /**
+ * This will schedule a cleanup of expired jobs based on configurable values
+ */
+ private void scheduleCleanUp() {
+
+
+ logger.fine(KernelLoggerInfo.schedulingCleanup);
+ //default values to 20 minutes for delayBetweenRuns and initialDelay
+ long delayBetweenRuns = 1200000;
+ long initialDelay = 1200000;
+
+ delayBetweenRuns = jobManagerService.convert(managedJobConfig.getPollInterval());
+ initialDelay = jobManagerService.convert(managedJobConfig.getInitialDelay());
+
+
+ ScheduledFuture<?> cleanupFuture = scheduler.scheduleAtFixedRate(new JobCleanUpTask(),initialDelay,delayBetweenRuns,TimeUnit.MILLISECONDS);
+
+ }
+
+ /**
+ * This method is notified for any changes in job-inactivity-limit or
+ * job-retention-period or persist, initial-delay or poll-interval option in
+ * ManagedJobConfig. Any change results
+ * in the job cleanup service to change the behaviour
+ * being updated.
+ * @param events the configuration change events.
+ * @return the unprocessed change events.
+ */
+ @Override
+ public UnprocessedChangeEvents changed(PropertyChangeEvent[] events) {
+ return ConfigSupport.sortAndDispatch(events, new PropertyChangeHandler(), logger);
+ }
+
+
+ private final class JobCleanUpTask implements Runnable {
+ public void run() {
+ try {
+ //This can have data when server starts up initially or as jobs complete
+ ConcurrentHashMap<String,CompletedJob> completedJobsMap = jobManagerService.getCompletedJobsInfo();
+
+ Iterator<CompletedJob> completedJobs = new HashSet<CompletedJob>(completedJobsMap.values()).iterator();
+ while (completedJobs.hasNext() ) {
+ CompletedJob completedJob = completedJobs.next();
+
+ logger.log(Level.FINE,KernelLoggerInfo.cleaningJob, new Object[]{completedJob.getId()});
+
+ cleanUpExpiredJobs(completedJob.getJobsFile());
+ }
+ } catch (Exception e ) {
+ throw new RuntimeException(KernelLoggerInfo.exceptionCleaningJobs,e);
+ }
+
+ }
+
+
+ }
+
+ /**
+ * This will periodically purge expired jobs
+ */
+ private void cleanUpExpiredJobs(File file) {
+ ArrayList<JobInfo> expiredJobs = jobManagerService.getExpiredJobs(file);
+ if (expiredJobs.size() > 0 ) {
+ for (JobInfo job: expiredJobs) {
+ //remove from Job registy
+ jobManagerService.purgeJob(job.jobId);
+ //remove from jobs.xml file
+ jobManagerService.purgeCompletedJobForId(job.jobId,file);
+ //remove from local cache for completed jobs
+ jobManagerService.removeFromCompletedJobs(job.jobId);
+ if(logger.isLoggable(Level.FINE)) {
+ logger.log(Level.FINE,KernelLoggerInfo.cleaningJob, job.jobId);
+ }
+ }
+ }
+
+ }
+
+
+ class PropertyChangeHandler implements Changed {
+
+ @Override
+ public <T extends ConfigBeanProxy> NotProcessed changed(TYPE type, Class<T> changedType, T changedInstance) {
+ NotProcessed np = null;
+ switch (type) {
+ case CHANGE:
+ if(logger.isLoggable(Level.FINE)) {
+
+ logger.log(Level.FINE, KernelLoggerInfo.changeManagedJobConfig, new Object[]{
+ changedType.getName()
+ ,changedInstance.toString()});
+ }
+ np = handleChangeEvent(changedInstance);
+ break;
+ default:
+ }
+ return np;
+ }
+
+ private <T extends ConfigBeanProxy> NotProcessed handleChangeEvent(T instance) {
+ scheduleCleanUp();
+ return null;
+ }
+ }
+}
+
+
+
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobCreatorService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobCreatorService.java
new file mode 100644
index 0000000..d895728
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobCreatorService.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.glassfish.api.admin.Job;
+import org.glassfish.api.admin.JobCreator;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Inject;
+import javax.security.auth.Subject;
+import java.io.File;
+import org.glassfish.api.admin.ParameterMap;
+
+/**
+ * This service implements the <code>JobCreator</code> and is
+ * used for creating Jobs
+ * @author Bhakti Mehta
+ */
+@Service (name="job-creator")
+public class JobCreatorService implements JobCreator {
+
+ @Inject
+ private ServerEnvironment serverEnvironment;
+
+ @Inject JobManagerService jobManagerService;
+
+ private static final String JOBS_FILE = "jobs.xml";
+ /**
+ * This will create a new job with the name of command and a new unused id for the job
+ *
+ *
+ * @param scope The scope of the command or null if there is no scope
+ * @param name The name of the command
+ * @return a newly created job
+ */
+ @Override
+ public Job createJob(String id, String scope, String name, Subject subject, boolean isManagedJob, ParameterMap parameters) {
+ AdminCommandInstanceImpl job = null;
+ if (isManagedJob) {
+ job = new AdminCommandInstanceImpl(id, name, scope, subject, true, parameters);
+ job.setJobsFile(jobManagerService.jobsFile);
+ } else {
+ job = new AdminCommandInstanceImpl(name, scope, subject, false, parameters);
+ }
+ return job;
+ }
+
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobFileScanner.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobFileScanner.java
new file mode 100644
index 0000000..c8c158f
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobFileScanner.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.glassfish.api.admin.JobLocator;
+import javax.inject.Singleton;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * This service will scan for all jobs.xml
+ * @author Bhakti Mehta
+ */
+@Service (name="job-filescanner")
+@Singleton
+public class JobFileScanner implements PostConstruct {
+
+ @Inject
+ private ServiceLocator serviceLocator;
+
+ HashSet<File> persistedJobFiles ;
+
+ @Override
+ public void postConstruct() {
+
+ Collection<JobLocator> services = serviceLocator.getAllServices(JobLocator.class);
+ persistedJobFiles = new HashSet<File>() ;
+ for (JobLocator locator: services) {
+ persistedJobFiles.addAll(locator.locateJobXmlFiles());
+ }
+ }
+
+ public HashSet<File> getJobFiles() {
+ return persistedJobFiles;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobLocatorService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobLocatorService.java
new file mode 100644
index 0000000..2df48e5
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobLocatorService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.glassfish.api.admin.JobLocator;
+import org.jvnet.hk2.annotations.Service;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * This service will look for completed jobs from the jobs.xml
+ * files and load the information
+ *
+ * @author Bhakti Mehta
+ */
+@Service(name = "job-locator")
+public class JobLocatorService implements JobLocator {
+
+ protected Set<File> jobFiles = (Set<File>) Collections.synchronizedSet(new HashSet<File>());
+
+ @Override
+ public Set<File> locateJobXmlFiles() {
+ return jobFiles;
+ }
+
+
+ public void addFile(File file) {
+ jobFiles.add(file);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobManagerService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobManagerService.java
new file mode 100644
index 0000000..025e7fc
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobManagerService.java
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.admin.event.AdminCommandEventBrokerImpl;
+import com.sun.enterprise.admin.remote.RestPayloadImpl;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.ManagedJobConfig;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.StringUtils;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import com.sun.enterprise.v3.admin.CheckpointHelper.CheckpointFilename;
+import com.sun.enterprise.v3.server.ExecutorServiceFactory;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.glassfish.api.admin.*;
+import org.glassfish.api.admin.progress.JobInfo;
+import org.glassfish.api.admin.progress.JobInfos;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.api.event.RestrictTo;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+import javax.xml.bind.Marshaller;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.AdminCommandState.State;
+
+/**
+ * This is the implementation for the JobManagerService
+ * The JobManager is responsible
+ * 1. generating unique ids for jobs
+ * 2. serving as a registry for jobs
+ * 3. creating threadpools for jobs
+ * 4.removing expired jobs
+ *
+ * @author Martin Mares
+ * @author Bhakti Mehta
+ */
+
+@Service(name="job-manager")
+@Singleton
+public class JobManagerService implements JobManager, PostConstruct, EventListener {
+
+ private static final String CHECKPOINT_MAINDATA = "MAINCMD";
+
+ @Inject
+ private Domain domain;
+
+ private ManagedJobConfig managedJobConfig;
+
+ private static final int MAX_SIZE = 65535;
+
+ private final ConcurrentHashMap<String, Job> jobRegistry = new ConcurrentHashMap<String, Job>();
+
+ private final AtomicInteger lastId = new AtomicInteger(0);
+
+ protected static final LocalStringManagerImpl adminStrings =
+ new LocalStringManagerImpl(JobManagerService.class);
+
+ private final static Logger logger = KernelLoggerInfo.getLogger();
+
+ private ExecutorService pool;
+
+ @Inject
+ private ExecutorServiceFactory executorFactory;
+
+ @Inject
+ private ServerEnvironment serverEnvironment;
+
+ private final String JOBS_FILE = "jobs.xml";
+
+ protected JAXBContext jaxbContext;
+
+ protected File jobsFile;
+
+ @Inject
+ private ServiceLocator serviceLocator;
+
+ @Inject
+ private JobFileScanner jobFileScanner;
+
+ @Inject
+ Events events;
+
+ @Inject
+ CheckpointHelper checkpointHelper;
+
+ @Inject
+ CommandRunnerImpl commandRunner;
+
+ // This will store the data related to completed jobs so that unique ids
+ // can be generated for new jobs. This is populated lazily the first
+ // time the JobManagerService is created, it will scan the
+ //jobs.xml and load the information in memory
+ private final ConcurrentHashMap<String, CompletedJob> completedJobsInfo = new ConcurrentHashMap<String, CompletedJob>();
+ private final ConcurrentHashMap<String, CheckpointFilename> retryableJobsInfo = new ConcurrentHashMap<String, CheckpointFilename>();
+
+ /**
+ * This will return a new id which is unused
+ * @return
+ */
+ @Override
+ public synchronized String getNewId() {
+
+ int nextId = lastId.incrementAndGet();
+ if (nextId > MAX_SIZE) {
+ reset();
+ }
+ String nextIdToUse = String.valueOf(nextId);
+ return !idInUse(nextIdToUse) ? String.valueOf(nextId): getNewId();
+ }
+
+ public JobInfo getCompletedJobForId(String id, File file) {
+ for (JobInfo jobInfo: getCompletedJobs(file).getJobInfoList()) {
+ if (jobInfo.jobId.equals(id)) {
+ return jobInfo;
+ }
+
+ }
+ return null;
+ }
+
+ @Override
+ public JobInfo getCompletedJobForId(String id) {
+ return getCompletedJobForId(id,getJobsFile());
+ }
+
+
+ /**
+ * This resets the id to 0
+ */
+ private void reset() {
+ lastId.set(0);
+ }
+
+ /**
+ * This method will return if the id is in use
+ * @param id
+ * @return true if id is in use
+ */
+ private boolean idInUse(String id) {
+ return jobRegistry.containsKey(id)
+ || completedJobsInfo.containsKey(id)
+ || retryableJobsInfo.containsKey(id);
+ }
+
+
+
+ /**
+ * This adds the jobs
+ * @param job
+ * @throws IllegalArgumentException
+ */
+ @Override
+ public synchronized void registerJob(Job job) throws IllegalArgumentException {
+ if (job == null) {
+ throw new IllegalArgumentException(adminStrings.getLocalString("job.cannot.be.null","Job cannot be null"));
+ }
+ if (jobRegistry.containsKey(job.getId())) {
+ throw new IllegalArgumentException(adminStrings.getLocalString("job.id.in.use","Job id is already in use."));
+ }
+
+ retryableJobsInfo.remove(job.getId());
+ jobRegistry.put(job.getId(), job);
+
+ if (job.getState() == State.PREPARED && (job instanceof AdminCommandInstanceImpl)) {
+ ((AdminCommandInstanceImpl) job).setState(AdminCommandState.State.RUNNING);
+ }
+ }
+
+ /**
+ * This returns all the jobs in the registry
+ * @return The iterator of jobs
+ */
+ @Override
+ public Iterator<Job> getJobs() {
+ return jobRegistry.values().iterator();
+ }
+
+ /**
+ * This will return a job associated with the id
+ * @param id The job whose id matches
+ * @return
+ */
+ @Override
+ public Job get(String id) {
+ return jobRegistry.get(id);
+ }
+
+ /**
+ * This will return a list of jobs which have crossed the JOBS_RETENTION_PERIOD
+ * and need to be purged
+ * @return list of jobs to be purged
+ */
+ public ArrayList<JobInfo> getExpiredJobs(File file) {
+ ArrayList<JobInfo> expiredJobs = new ArrayList<JobInfo>();
+ synchronized (file) {
+ JobInfos jobInfos = getCompletedJobs(file);
+ for(JobInfo job:jobInfos.getJobInfoList()) {
+
+ long executedTime = job.commandExecutionDate;
+ long currentTime = System.currentTimeMillis();
+
+ long jobsRetentionPeriod = 86400000;
+
+
+ managedJobConfig = domain.getExtensionByType(ManagedJobConfig.class);
+ jobsRetentionPeriod = convert(managedJobConfig.getJobRetentionPeriod());
+
+ if (currentTime - executedTime > jobsRetentionPeriod &&
+ (job.state.equals(AdminCommandState.State.COMPLETED.name()) ||
+ job.state.equals(AdminCommandState.State.REVERTED.name()))) {
+ expiredJobs.add(job);
+ }
+ }
+ }
+ return expiredJobs;
+ }
+
+ public long convert(String input ) {
+ String period = input.substring(0,input.length()-1);
+ Long timeInterval = new Long(period);
+ String s = input.toLowerCase(Locale.US);
+ long milliseconds = 86400000;
+ if (s.indexOf("s") > 0 ) {
+ milliseconds = timeInterval*1000;
+ }
+ else if (s.indexOf("h") > 0 ) {
+ milliseconds = timeInterval*3600*1000;
+
+ }
+ else if (s.indexOf("m") > 0 ) {
+ milliseconds = timeInterval*60*1000;
+ }
+ return milliseconds;
+ }
+
+
+ /**
+ * This will remove the job from the registry
+ * @param id The job id of the job to be removed
+ */
+ @Override
+ public synchronized void purgeJob(final String id) {
+ Job job = jobRegistry.remove(id);
+ logger.fine(adminStrings.getLocalString("removed.expired.job","Removed expired job ", job));
+ }
+
+ public void deleteCheckpoint(final File parentDir, final String jobId) {
+ //list all related files
+ File[] toDelete = parentDir.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.startsWith(jobId + ".") || name.startsWith(jobId + "-");
+ }
+ });
+ for (File td : toDelete) {
+ td.delete();
+ }
+ }
+
+ public ExecutorService getThreadPool() {
+ return pool ;
+ }
+
+
+ /**
+ * This will load the jobs which have already completed
+ * and persisted in the jobs.xml
+ * @return JobsInfos which contains information about completed jobs
+ */
+ @Override
+ public JobInfos getCompletedJobs(File jobsFile) {
+ synchronized (jobsFile) {
+ try {
+ if (jaxbContext == null)
+ jaxbContext = JAXBContext.newInstance(JobInfos.class);
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+
+ if (jobsFile != null && jobsFile.exists()) {
+ JobInfos jobInfos = (JobInfos)unmarshaller.unmarshal(jobsFile);
+ return jobInfos;
+ }
+ } catch (JAXBException e) {
+ throw new RuntimeException(adminStrings.getLocalString("error.reading.completed.jobs","Error reading completed jobs ", e.getLocalizedMessage()), e);
+ }
+ return null;
+ }
+ }
+
+ /**
+ * This method looks for the completed jobs
+ * and purges a job which is marked with the jobId
+ * @param jobId the job to purge
+ * @return the new list of completed jobs
+ */
+
+ public JobInfos purgeCompletedJobForId(String jobId, File file) {
+ JobInfos completedJobInfos = getCompletedJobs(file);
+ synchronized (file) {
+ CopyOnWriteArrayList<JobInfo> jobList = new CopyOnWriteArrayList<JobInfo>();
+
+ if (completedJobInfos != null) {
+ jobList.addAll(completedJobInfos.getJobInfoList());
+
+ for (JobInfo jobInfo: jobList ) {
+ if (jobInfo.jobId.equals(jobId)) {
+ jobList.remove(jobInfo);
+ }
+
+ }
+ }
+
+ JobInfos jobInfos = new JobInfos();
+ // if (jobList.size() > 0) {
+ try {
+ if (jaxbContext == null)
+ jaxbContext = JAXBContext.newInstance(JobInfos.class);
+
+ jobInfos.setJobInfoList(jobList);
+ Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
+ jaxbMarshaller.marshal(jobInfos, file);
+ } catch (JAXBException e) {
+ throw new RuntimeException(adminStrings.getLocalString("error.purging.completed.job","Error purging completed job ", jobId,e.getLocalizedMessage()), e);
+ }
+ //}
+ return jobInfos;
+ }
+
+ }
+
+ @Override
+ public JobInfos purgeCompletedJobForId(String id) {
+ return purgeCompletedJobForId(id, getJobsFile()) ;
+ }
+
+
+ @Override
+ public void postConstruct() {
+ jobsFile =
+ new File(serverEnvironment.getConfigDirPath(),JOBS_FILE);
+
+ pool = executorFactory.provide();
+
+ HashSet<File> persistedJobFiles = jobFileScanner.getJobFiles();
+ persistedJobFiles.add(jobsFile);
+
+ // Check if there are jobs.xml files which have completed jobs so that
+ // unique ids get generated
+ for (File jobfile : persistedJobFiles) {
+ if (jobfile != null) {
+ reapCompletedJobs(jobfile);
+ boolean dropInterruptedCommands = Boolean.valueOf(System.getProperty(SystemPropertyConstants.DROP_INTERRUPTED_COMMANDS));
+ Collection<CheckpointFilename> listed = checkpointHelper.listCheckpoints(jobfile.getParentFile());
+ for (CheckpointFilename cf : listed) {
+ if (dropInterruptedCommands) {
+ logger.info("Dropping checkpoint: " + cf.getFile());
+ deleteCheckpoint(cf.getParentDir(), cf.getJobId());
+ } else {
+ this.retryableJobsInfo.put(cf.getJobId(), cf);
+ }
+ }
+ }
+ }
+ events.register(this);
+ }
+
+ @Override
+ public File getJobsFile() {
+ return jobsFile;
+ }
+
+ public void addToCompletedJobs(CompletedJob job) {
+ completedJobsInfo.put(job.getId(),job);
+
+ }
+
+ public void removeFromCompletedJobs(String id) {
+ completedJobsInfo.remove(id);
+ }
+
+ public ConcurrentHashMap<String, CompletedJob> getCompletedJobsInfo() {
+ return completedJobsInfo;
+ }
+
+ public ConcurrentHashMap<String, CheckpointFilename> getRetryableJobsInfo() {
+ return retryableJobsInfo;
+ }
+
+ @Override
+ public void checkpoint(AdminCommandContext context, Serializable data) throws IOException {
+ checkpoint((AdminCommand) null, context);
+ if (data != null) {
+ checkpointAttachement(context.getJobId(), CHECKPOINT_MAINDATA, data);
+ }
+ }
+
+ @Override
+ public void checkpoint(AdminCommand command, AdminCommandContext context) throws IOException {
+ if (!StringUtils.ok(context.getJobId())) {
+ throw new IllegalArgumentException("Command is not managed");
+ }
+ Job job = get(context.getJobId());
+ if (job.getJobsFile() == null) {
+ job.setJobsFile(getJobsFile());
+ }
+ Checkpoint chkp = new Checkpoint(job, command, context);
+ checkpointHelper.save(chkp);
+ if (job instanceof AdminCommandInstanceImpl) {
+ ((AdminCommandInstanceImpl) job).setState(AdminCommandState.State.RUNNING_RETRYABLE);
+ }
+ }
+
+ public void checkpointAttachement(String jobId, String attachId, Serializable data) throws IOException {
+ Job job = get(jobId);
+ if (job.getJobsFile() == null) {
+ job.setJobsFile(getJobsFile());
+ }
+ checkpointHelper.saveAttachment(data, job, attachId);
+ }
+
+ public <T extends Serializable> T loadCheckpointAttachement(String jobId, String attachId) throws IOException, ClassNotFoundException {
+ Job job = get(jobId);
+ if (job.getJobsFile() == null) {
+ job.setJobsFile(getJobsFile());
+ }
+ return checkpointHelper.loadAttachment(job, attachId);
+ }
+
+ @Override
+ public Serializable loadCheckpointData(String jobId) throws IOException, ClassNotFoundException {
+ return loadCheckpointAttachement(jobId, CHECKPOINT_MAINDATA);
+ }
+
+ public Checkpoint loadCheckpoint(String jobId, Payload.Outbound outbound) throws IOException, ClassNotFoundException {
+ Job job = get(jobId);
+ CheckpointFilename cf = null;
+ if (job == null) {
+ cf = getRetryableJobsInfo().get(jobId);
+ if (cf == null) {
+ cf = CheckpointFilename.createBasic(jobId, getJobsFile());
+ }
+ } else {
+ cf = CheckpointFilename.createBasic(job);
+ }
+ return loadCheckpoint(cf, outbound);
+ }
+
+ private Checkpoint loadCheckpoint(CheckpointFilename cf, Payload.Outbound outbound) throws IOException, ClassNotFoundException {
+ Checkpoint result = checkpointHelper.load(cf, outbound);
+ if (result != null) {
+ serviceLocator.inject(result.getJob());
+ serviceLocator.postConstruct(result.getJob());
+ if (result.getCommand() != null) {
+ serviceLocator.inject(result.getCommand());
+ serviceLocator.postConstruct(result.getCommand());
+ }
+ }
+ return result;
+ }
+
+ /* This method will look for completed jobs from the jobs.xml
+ * files and load the information in a local datastructure for
+ * faster access
+ */
+ protected void reapCompletedJobs(File file) {
+ if (file != null && file.exists()) {
+ JobInfos jobInfos = getCompletedJobs(file);
+ if (jobInfos != null) {
+ for (JobInfo jobInfo: jobInfos.getJobInfoList()) {
+ addToCompletedJobs(new CompletedJob(jobInfo.jobId,jobInfo.commandCompletionDate,jobInfo.getJobsFile()));
+ }
+ }
+ }
+ }
+
+ @Override
+ public void event(@RestrictTo(EventTypes.SERVER_READY_NAME) Event event) {
+ if (event.is(EventTypes.SERVER_READY)) {
+ if (retryableJobsInfo.size() > 0) {
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ logger.fine("Restarting retryable jobs");
+ for (CheckpointFilename cf : retryableJobsInfo.values()) {
+ reexecuteJobFromCheckpoint(cf);
+ }
+ }
+ };
+ (new Thread(runnable)).start();
+ } else {
+ logger.fine("No retryable job found");
+ }
+ }
+ }
+
+ private void reexecuteJobFromCheckpoint(CheckpointFilename cf) {
+ Checkpoint checkpoint = null;
+ try {
+ RestPayloadImpl.Outbound outbound = new RestPayloadImpl.Outbound(true);
+ checkpoint = loadCheckpoint(cf, outbound);
+ } catch (Exception ex) {
+ logger.log(Level.WARNING, KernelLoggerInfo.exceptionLoadCheckpoint, ex);
+ }
+ if (checkpoint != null) {
+ logger.log(Level.INFO, KernelLoggerInfo.checkpointAutoResumeStart,
+ new Object[]{checkpoint.getJob().getName()});
+ commandRunner.executeFromCheckpoint(checkpoint, false, new AdminCommandEventBrokerImpl());
+ ActionReport report = checkpoint.getContext().getActionReport();
+ logger.log(Level.INFO, KernelLoggerInfo.checkpointAutoResumeDone,
+ new Object[]{checkpoint.getJob().getName(), report.getActionExitCode(), report.getTopMessagePart()});
+ }
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobPersistenceService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobPersistenceService.java
new file mode 100644
index 0000000..939fe81
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/JobPersistenceService.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import java.io.File;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import org.glassfish.api.admin.progress.JobInfo;
+import org.glassfish.api.admin.progress.JobInfos;
+import org.glassfish.api.admin.progress.JobPersistence;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+
+
+/**
+ * This service persists information for managed jobs to the file
+ * @author Bhakti Mehta
+ */
+@Service(name="job-persistence")
+public class JobPersistenceService implements JobPersistence {
+
+ protected Marshaller jaxbMarshaller ;
+
+ protected Unmarshaller jaxbUnmarshaller;
+
+ protected JobInfos jobInfos;
+
+ @Inject
+ private JobManagerService jobManager;
+
+ protected JAXBContext jaxbContext;
+
+ protected final static Logger logger = KernelLoggerInfo.getLogger();
+
+
+ protected static final LocalStringManagerImpl adminStrings =
+ new LocalStringManagerImpl(JobPersistenceService.class);
+ @Override
+ public void persist(Object obj) {
+ JobInfo jobInfo = (JobInfo)obj;
+
+ jobInfos = jobManager.getCompletedJobs(jobManager.getJobsFile());
+
+ doPersist(jobInfos,jobInfo);
+
+ }
+
+ public void doPersist(JobInfos jobInfos, JobInfo jobInfo) {
+ File file = jobInfo.getJobsFile();
+ synchronized (file) {
+
+ if (jobInfos == null) {
+ jobInfos = new JobInfos();
+ }
+
+ try {
+ JAXBContext jaxbContext = JAXBContext.newInstance(JobInfos.class);
+ jaxbMarshaller = jaxbContext.createMarshaller();
+ jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+
+ CopyOnWriteArrayList<JobInfo> jobList = new CopyOnWriteArrayList<JobInfo>(jobInfos.getJobInfoList());
+ jobInfos.setJobInfoList(jobList);
+ jobList.add(jobInfo);
+ jaxbMarshaller.marshal(jobInfos, file);
+ jobManager.addToCompletedJobs(new CompletedJob(jobInfo.jobId,jobInfo.commandCompletionDate,jobInfo.getJobsFile()));
+ jobManager.purgeJob(jobInfo.jobId);
+
+ } catch (JAXBException e) {
+ throw new RuntimeException(adminStrings.getLocalString("error.persisting.jobs","Error while persisting jobs",jobInfo.jobId,e.getLocalizedMessage()),e);
+
+ }
+ }
+ }
+
+
+
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListCommand.java
new file mode 100644
index 0000000..25996b6
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListCommand.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.admin.util.ClusterOperationUtil;
+import com.sun.enterprise.config.serverbeans.Server;
+import org.glassfish.api.admin.*;
+import org.glassfish.internal.api.Target;
+import org.jvnet.hk2.annotations.Optional;
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.jvnet.hk2.config.Dom;
+import org.glassfish.api.Param;
+import org.glassfish.api.ActionReport;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import java.util.*;
+
+import com.sun.enterprise.v3.common.PropsFileActionReporter;
+import org.glassfish.api.ActionReport.ExitCode;
+import org.glassfish.flashlight.MonitoringRuntimeDataRegistry;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import org.glassfish.api.admin.AccessRequired.AccessCheck;
+
+/**
+ * User: Jerome Dochez
+ * Date: Jul 12, 2008
+ * Time: 1:27:53 AM
+ */
+@Service(name="list")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+public class ListCommand extends V2DottedNameSupport implements AdminCommand,
+ AdminCommandSecurity.Preauthorization, AdminCommandSecurity.AccessCheckProvider {
+
+ @Inject
+ private MonitoringReporter mr;
+
+ @Inject
+ Domain domain;
+
+ @Inject
+ ServerEnvironment serverEnv;
+
+ @Inject
+ Target targetService;
+
+ @Inject
+ ServiceLocator habitat;
+
+ //How to define short option name?
+ @Param(name="MoniTor", optional=true, defaultValue="false", shortName="m", alias="Mon")
+ Boolean monitor;
+
+ @Param(primary = true)
+ String pattern="";
+
+ @Inject @Optional
+ private MonitoringRuntimeDataRegistry mrdr;
+
+ private Map<Dom, String> matchingNodes;
+
+ private TreeNode[] parentNodes;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ if (monitor) {
+ return preAuthorizationForMonitoring(context);
+ } else {
+ return preAuthorizationForNonMonitoring(context);
+ }
+ }
+
+ private boolean preAuthorizationForMonitoring(final AdminCommandContext context) {
+ mr.prepareList(context, pattern);
+ return true;
+ }
+
+ private boolean preAuthorizationForNonMonitoring(final AdminCommandContext context) {
+ // first let's get the parent for this pattern.
+ parentNodes = getAliasedParent(domain, pattern);
+ Map<Dom, String> dottedNames = new HashMap<Dom, String>();
+ for (TreeNode parentNode : parentNodes) {
+ dottedNames.putAll(getAllDottedNodes(parentNode.node));
+ }
+ // reset the pattern.
+ pattern = parentNodes[0].relativeName;
+
+ matchingNodes = getMatchingNodes(dottedNames, pattern);
+ if (matchingNodes.isEmpty() && pattern.lastIndexOf('.')!=-1) {
+ // it's possible the user is just looking for an attribute, let's remove the
+ // last element from the pattern.
+ matchingNodes = getMatchingNodes(dottedNames, pattern.substring(0, pattern.lastIndexOf(".")));
+ }
+ return true;
+ }
+
+ @Override
+ public Collection<? extends AccessCheck> getAccessChecks() {
+ if (monitor) {
+ return getAccessChecksForMonitoring();
+ } else {
+ return getAccessChecksForNonMonitoring();
+ }
+ }
+
+ private Collection<? extends AccessCheck> getAccessChecksForMonitoring() {
+ return mr.getAccessChecksForList();
+ }
+
+ private Collection<? extends AccessCheck> getAccessChecksForNonMonitoring() {
+ final Collection<AccessCheck> accessChecks = new ArrayList<AccessCheck>();
+ for (Map.Entry<Dom,String> entry : matchingNodes.entrySet()) {
+ accessChecks.add(new AccessCheck(AccessRequired.Util.resourceNameFromDom((Dom)entry.getKey()), "read"));
+ }
+ return accessChecks;
+ }
+
+ public void execute(AdminCommandContext context) {
+
+ ActionReport report = context.getActionReport();
+
+ /* Issue 5918 Used in ManifestManager to keep output sorted */
+ try {
+ PropsFileActionReporter reporter = (PropsFileActionReporter) report;
+ reporter.useMainChildrenAttribute(true);
+ } catch(ClassCastException e) {
+ // ignore, this is not a manifest output
+ }
+
+ if (monitor) {
+ listMonitorElements(context);
+ return;
+ }
+
+ List<Map.Entry> matchingNodesSorted = sortNodesByDottedName(matchingNodes);
+ for (Map.Entry<Dom, String> node : matchingNodesSorted) {
+ ActionReport.MessagePart part = report.getTopMessagePart().addChild();
+ part.setChildrenType("DottedName");
+ if (parentNodes[0].name.isEmpty()) {
+ part.setMessage(node.getValue());
+ } else {
+ part.setMessage(parentNodes[0].name + "." + node.getValue());
+ }
+ }
+ }
+
+ private void listMonitorElements(AdminCommandContext ctxt) {
+ mr.execute();
+ }
+
+ public void callInstance(ActionReport report, AdminCommandContext context, String targetName) {
+ try {
+ ParameterMap paramMap = new ParameterMap();
+ paramMap.set("MoniTor", "true");
+ paramMap.set("DEFAULT", pattern);
+ List<Server> targetList = targetService.getInstances(targetName);
+ ClusterOperationUtil.replicateCommand("list", FailurePolicy.Error, FailurePolicy.Warn,
+ FailurePolicy.Ignore, targetList, context, paramMap, habitat);
+ } catch(Exception ex) {
+ report.setActionExitCode(ExitCode.FAILURE);
+ report.setMessage("Failure while trying get details from instance " + targetName);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListCommandDescriptorsCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListCommandDescriptorsCommand.java
new file mode 100644
index 0000000..aecb209
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListCommandDescriptorsCommand.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.universal.collections.ManifestUtils;
+import java.lang.reflect.Field;
+import java.util.*;
+import javax.inject.Inject;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.AccessRequired;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Create data structures that describe the command.
+ *
+ * @author Jerome Dochez
+ *
+ */
+@Service(name="_list-descriptors")
+@PerLookup
+@I18n("list.commands")
+@AccessRequired(resource="domain", action="dump")
+public class ListCommandDescriptorsCommand implements AdminCommand {
+ @Inject
+ ServiceLocator habitat;
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ setAdminCommands();
+ sort();
+
+ for (AdminCommand cmd : adminCmds) {
+ cliCmds.add(reflect(cmd));
+ }
+ ActionReport report = context.getActionReport();
+ StringBuilder sb = new StringBuilder();
+ sb.append("ALL COMMANDS: ").append(EOL);
+ for(CLICommand cli : cliCmds) {
+ sb.append(cli.toString()).append(EOL);
+ }
+ report.setMessage(sb.toString());
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+
+ private CLICommand reflect(AdminCommand cmd) {
+ CLICommand cliCmd = new CLICommand(cmd);
+
+ for (Field f : cmd.getClass().getDeclaredFields()) {
+ final Param param = f.getAnnotation(Param.class);
+ if (param==null)
+ continue;
+
+ Option option = new Option(param, f);
+ cliCmd.options.add(option);
+ }
+ return cliCmd;
+ }
+
+ private void setAdminCommands() {
+ adminCmds = new ArrayList<AdminCommand>();
+ for (AdminCommand command : habitat.<AdminCommand>getAllServices(AdminCommand.class)) {
+ adminCmds.add(command);
+ }
+ }
+
+ private void sort() {
+ Collections.sort(adminCmds, new Comparator<AdminCommand>() {
+ @Override
+ public int compare(AdminCommand c1, AdminCommand c2) {
+ Service service1 = c1.getClass().getAnnotation(Service.class);
+ Service service2 = c2.getClass().getAnnotation(Service.class);
+
+ String name1 = (service1 != null) ? service1.name() : "";
+ String name2 = (service2 != null) ? service2.name() : "";
+
+ return name1.compareTo(name2);
+ }
+ }
+ );
+ }
+
+ private static boolean ok(String s) {
+ return s != null && s.length() > 0 && !s.equals("null");
+ }
+
+ private List<AdminCommand> adminCmds;
+ private List<CLICommand> cliCmds = new LinkedList<CLICommand>();
+ private final static String EOL = ManifestUtils.EOL_TOKEN;
+
+ private static class CLICommand {
+ CLICommand(AdminCommand adminCommand) {
+ this.adminCommand = adminCommand;
+ Service service = adminCommand.getClass().getAnnotation(Service.class);
+ name = (service != null) ? service.name() : "";
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("CLI Command: name=").append(name);
+ sb.append(" class=").append(adminCommand.getClass().getName()).append(EOL);
+
+ for(Option opt : options) {
+ sb.append(opt.toString()).append(EOL);
+ }
+ return sb.toString();
+ }
+
+ AdminCommand adminCommand;
+ String name;
+ List<Option> options = new LinkedList<Option>();
+ }
+ private static class Option {
+ Option(Param p, Field f) {
+ final Class<?> ftype = f.getType();
+ name = p.name();
+
+ if(!ok(name)) {
+ name = f.getName();
+ }
+
+ required = !p.optional();
+ operand = p.primary();
+ defaultValue = p.defaultValue();
+ type = ftype;
+ }
+ @Override
+ public String toString() {
+ String s = " Option:" +
+ " name=" + name +
+ " required=" + required +
+ " operand=" + operand +
+ " defaultValue=" + defaultValue +
+ " type=" + type.getName();
+ return s;
+ }
+
+ private boolean required;
+ private boolean operand;
+ private String name;
+ private String defaultValue;
+ private Class<?> type;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListCommandsCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListCommandsCommand.java
new file mode 100644
index 0000000..3ea199b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListCommandsCommand.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.*;
+import org.glassfish.hk2.api.ActiveDescriptor;
+import org.glassfish.hk2.api.ServiceHandle;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Simple admin command to list all existing commands.
+ *
+ * @author Jerome Dochez
+ *
+ */
+@Service(name="list-commands")
+@Singleton // no per-execution state
+@CommandLock(CommandLock.LockType.NONE)
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="list-commands",
+ description="list-commands")
+})
+@AccessRequired(resource="domain", action="read")
+public class ListCommandsCommand implements AdminCommand {
+ private static final String MODE = "mode";
+ private static final String DEBUG = "debug";
+
+ @Inject
+ ServiceLocator habitat;
+
+
+ /**
+ * Executes the command with the command parameters passed as Properties
+ * where the keys are the paramter names and the values the parameter values
+ *
+ * @param context information
+ */
+ @Override
+ public void execute(AdminCommandContext context) {
+
+ context.getActionReport().setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ ActionReport report = context.getActionReport();
+ report.getTopMessagePart().setChildrenType("Command");
+ for (String name : sortedAdminCommands()) {
+ ActionReport.MessagePart part = report.getTopMessagePart().addChild();
+ part.setMessage(name);
+ }
+ }
+
+ protected String getScope() {
+ return null;
+ }
+
+ private List<String> sortedAdminCommands() {
+ String scope = getScope();
+ List<String> names = new ArrayList<String>();
+ for (ServiceHandle<?> command : habitat.getAllServiceHandles(AdminCommand.class)) {
+ String name = command.getActiveDescriptor().getName() ;
+ //see 6161 -- I thought we should ensure that a command found in habitat should
+ //return a valid Command Object, but it was decided that we don't need to instantiate
+ //each object satisfying AdminCommand contract to get a list of all commands
+
+ // limit list to commands for current scope
+ if (name != null) {
+ int ci = name.indexOf("/");
+ if (ci != -1) {
+ String cmdScope = name.substring(0, ci + 1);
+ if (scope == null || !cmdScope.equals(scope)) continue;
+ name = name.substring(ci + 1);
+ } else {
+ if (scope != null) continue;
+ }
+
+ if (debugCommand(command) ) { //it's a debug command, add only if debug is set
+ if (debugSet())
+ names.add(name);
+ } else { //always add non-debug commands \
+ names.add(name);
+ }
+ }
+ }
+ Collections.sort(names);
+ return (names);
+
+ }
+
+ private static boolean debugCommand(ServiceHandle<?> command) {
+ ActiveDescriptor<?> ad = command.getActiveDescriptor();
+ Map<String, List<String>> metadata = ad.getMetadata();
+
+ List<String> modes = metadata.get(MODE);
+ if (modes == null) return false;
+
+ for (String mode : modes) {
+ if (DEBUG.equals(mode)) return true;
+ }
+
+ return false;
+ }
+
+ private static boolean debugSet() { //TODO take into a/c debug-enabled?
+ String s = System.getenv("AS_DEBUG");
+ return ( Boolean.valueOf(s) );
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListContainersCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListContainersCommand.java
new file mode 100644
index 0000000..f3c942f
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListContainersCommand.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.data.EngineInfo;
+import org.glassfish.internal.data.ContainerRegistry;
+import com.sun.enterprise.module.Module;
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.config.serverbeans.Application;
+import com.sun.enterprise.config.serverbeans.Applications;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.Engine;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.container.Sniffer;
+import javax.inject.Inject;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Singleton;
+
+/**
+ * This admin command list the containers currentely running within that
+ * Glassfish instance
+ */
+@Service(name="list-containers")
+@Singleton // no per-execution state
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("list.containers.command")
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="list-containers",
+ description="list-containers")
+})
+@AccessRequired(resource="domain", action="read")
+public class ListContainersCommand implements AdminCommand {
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ListContainersCommand.class);
+
+ @Inject
+ ContainerRegistry containerRegistry;
+
+ @Inject
+ ModulesRegistry modulesRegistry;
+
+ @Inject
+ ServiceLocator habitat;
+
+ @Inject
+ Applications applications;
+
+ public void execute(AdminCommandContext context) {
+
+ ActionReport report = context.getActionReport();
+ report.setActionDescription(localStrings.getLocalString("list.containers.command", "List of Containers"));
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+
+ ActionReport.MessagePart top = report.getTopMessagePart();
+ top.setMessage(localStrings.getLocalString("list.containers.command", "List of Containers"));
+ top.setChildrenType(localStrings.getLocalString("container", "Container"));
+
+ Iterable<? extends Sniffer> sniffers = habitat.getAllServices(Sniffer.class);
+ if (sniffers ==null) {
+ top.setMessage(localStrings.getLocalString("list.containers.nocontainer",
+ "No container currently configured"));
+ } else {
+ for (Sniffer sniffer : sniffers) {
+ ActionReport.MessagePart container = top.addChild();
+ container.setMessage(sniffer.getModuleType());
+ container.addProperty(localStrings.getLocalString("contractprovider", "ContractProvider"),
+ sniffer.getModuleType());
+ EngineInfo engineInfo = containerRegistry.getContainer(sniffer.getModuleType());
+
+ if (engineInfo != null) {
+ container.addProperty(
+ localStrings.getLocalString("status", "Status"),
+ localStrings.getLocalString("started", "Started"));
+ Module connectorModule = modulesRegistry.find(engineInfo.getSniffer().getClass());
+ container.addProperty(localStrings.getLocalString("connector", "Connector"),
+ connectorModule.getModuleDefinition().getName() +
+ ":" + connectorModule.getModuleDefinition().getVersion());
+ container.addProperty(localStrings.getLocalString("implementation", "Implementation"),
+ engineInfo.getContainer().getClass().toString());
+ boolean atLeastOne = false;
+ for (Application app : applications.getApplications()) {
+ for (com.sun.enterprise.config.serverbeans.Module module : app.getModule()) {
+ Engine engine = module.getEngine(engineInfo.getSniffer().getModuleType());
+ if (engine!=null) {
+ if (!atLeastOne) {
+ atLeastOne=true;
+ container.setChildrenType(localStrings.getLocalString("list.containers.listapps",
+ "Applications deployed"));
+
+ }
+ container.addChild().setMessage(app.getName());
+ }
+ }
+
+
+ }
+ if (!atLeastOne) {
+ container.addProperty("Status", "Not Started");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListModulesCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListModulesCommand.java
new file mode 100644
index 0000000..32ef09a
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListModulesCommand.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+
+import javax.inject.Singleton;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandLock;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.module.Module;
+import com.sun.enterprise.module.ModuleState;
+
+import java.net.URI;
+import org.glassfish.api.admin.*;
+
+/**
+ * List the modules available to this instance and their status
+ */
+@Service(name="list-modules")
+@Singleton // no per-execution state
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("list.modules.command")
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="list-modules",
+ description="list-modules")
+})
+@AccessRequired(resource="domain", action="dump")
+public class ListModulesCommand implements AdminCommand {
+
+ @Inject
+ ModulesRegistry registry;
+
+ public void execute(AdminCommandContext context) {
+
+ ActionReport report = context.getActionReport();
+ report.setActionDescription("List of modules");
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+
+ ActionReport.MessagePart top = report.getTopMessagePart();
+ top.setMessage("List Of Modules");
+ top.setChildrenType("Module");
+
+ StringBuilder sb = new StringBuilder("Module Status Report Begins\n");
+ // first started :
+
+ for (Module m : registry.getModules()) {
+ if (m.getState()== ModuleState.READY) {
+ sb.append(m).append("\n");
+ }
+ }
+ sb.append("\n");
+ // then resolved
+ for (Module m : registry.getModules()) {
+ if (m.getState()== ModuleState.RESOLVED) {
+ sb.append(m).append("\n");
+ }
+ }
+ sb.append("\n");
+ // finally installed
+ for (Module m : registry.getModules()) {
+ if (m.getState()!= ModuleState.READY && m.getState()!=ModuleState.RESOLVED) {
+ sb.append(m).append("\n");
+ }
+ }
+ sb.append("Module Status Report Ends");
+ ActionReport.MessagePart childPart = top.addChild();
+ childPart.setMessage(sb.toString());
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListSystemProperties.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListSystemProperties.java
new file mode 100644
index 0000000..c5096f8
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ListSystemProperties.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.SystemProperty;
+import com.sun.enterprise.config.serverbeans.SystemPropertyBag;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandLock;
+import org.glassfish.api.admin.ExecuteOn;
+import org.glassfish.api.admin.RuntimeType;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.*;
+import org.jvnet.hk2.config.types.Property;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Inject;
+import org.glassfish.hk2.api.PerLookup;
+
+/**
+ * List System Properties Command
+ *
+ * Lists the system properties of the domain, configuration, cluster, or server instance
+ *
+ * Usage: lists-system-properties [--terse={true|false}][ --echo={true|false} ]
+ * [ --interactive={true|false} ] [ --host host] [--port port] [--secure| -s ]
+ * [ --user admin_user] [--passwordfile filename] [--help] [target_name]
+ *
+ */
+@Service(name="list-system-properties")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@ExecuteOn({RuntimeType.DAS})
+@TargetType(value={CommandTarget.CLUSTER, CommandTarget.CLUSTERED_INSTANCE,
+CommandTarget.CONFIG, CommandTarget.DAS, CommandTarget.DOMAIN, CommandTarget.STANDALONE_INSTANCE})
+@I18n("list.system.properties")
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="list-system-properties",
+ description="list-system-properties")
+})
+public class ListSystemProperties implements AdminCommand, AdminCommandSecurity.Preauthorization,
+ AdminCommandSecurity.AccessCheckProvider {
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ListSystemProperties.class);
+
+ @Param(optional=true, primary=true, defaultValue=SystemPropertyConstants.DAS_SERVER_NAME)
+ String target;
+
+ @Inject
+ Domain domain;
+
+ private SystemPropertyBag spb;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ spb = CLIUtil.chooseTarget(domain, target);
+ if (spb == null) {
+ final ActionReport report = context.getActionReport();
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ String msg = localStrings.getLocalString("invalid.target.sys.props",
+ "Invalid target:{0}. Valid targets types are domain, config, cluster, default server, clustered instance, stand alone instance", target);
+ report.setMessage(msg);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public Collection<? extends AccessRequired.AccessCheck> getAccessChecks() {
+ final Collection<AccessRequired.AccessCheck> result = new ArrayList<AccessRequired.AccessCheck>();
+ result.add(new AccessRequired.AccessCheck(AccessRequired.Util.resourceNameFromConfigBeanProxy(spb), "update"));
+ return result;
+ }
+
+ /**
+ * Executes the command with the command parameters passed as Properties
+ * where the keys are the paramter names and the values the parameter values
+ *
+ * @param context information
+ */
+ @Override
+ public void execute(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+ try {
+ List<SystemProperty> sysProps = spb.getSystemProperty();
+ int length = 0;
+ if (sysProps.isEmpty()) {
+ final ActionReport.MessagePart part = report.getTopMessagePart().addChild();
+ part.setMessage(localStrings.getLocalString(
+ "NothingToList", "Nothing to List."));
+ } else {
+ for (SystemProperty prop : sysProps) {
+ final ActionReport.MessagePart part = report.getTopMessagePart().addChild();
+ part.setMessage(prop.getName()+"="+prop.getValue());
+ length++;
+ }
+ report.setMessage(localStrings.getLocalString("list.ok", "The target {0} contains following {1} system properties", target, length));
+ }
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ } catch (Exception e) {
+ report.setMessage(localStrings.getLocalString("list.system.properties.failed",
+ "list-system-properties failed"));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/LocalPasswordImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/LocalPasswordImpl.java
new file mode 100644
index 0000000..5bee18b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/LocalPasswordImpl.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import java.io.*;
+import java.security.SecureRandom;
+import java.util.logging.*;
+import javax.inject.Inject;
+import org.glassfish.api.admin.ServerEnvironment;
+
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.internal.api.*;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Manage a local password, which is a cryptographically secure random number
+ * stored in a file with permissions that only allow the owner to read it.
+ * A new local password is generated each time the server starts. The
+ * asadmin client can use it to authenticate when executing local commands,
+ * such as stop-domain, without the user needing to supply a password.
+ *
+ * @author Bill Shannon
+ */
+@Service
+@RunLevel(InitRunLevel.VAL)
+public class LocalPasswordImpl implements PostConstruct, LocalPassword {
+
+ @Inject
+ ServerEnvironment env;
+
+ private String password;
+
+ private static final String LOCAL_PASSWORD_FILE = "local-password";
+ private static final int PASSWORD_BYTES = 20;
+ private static final char[] hex = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ private static final Logger logger = KernelLoggerInfo.getLogger();
+
+ /**
+ * Generate a local password and save it in the local-password file.
+ */
+ public void postConstruct() {
+ logger.fine("Generating local password");
+ SecureRandom random = new SecureRandom();
+ byte[] pwd = new byte[PASSWORD_BYTES];
+ random.nextBytes(pwd);
+ password = toHex(pwd);
+ File localPasswordFile =
+ new File(env.getConfigDirPath(), LOCAL_PASSWORD_FILE);
+ PrintWriter w = null;
+ try {
+ if (localPasswordFile.exists()) {
+ if (!localPasswordFile.delete()) {
+ logger.log(Level.WARNING, KernelLoggerInfo.cantDeletePasswordFile,
+ localPasswordFile.toString());
+ // if we can't make sure it's our file, don't write it
+ return;
+ }
+ }
+ if (!localPasswordFile.createNewFile()) {
+ logger.log(Level.WARNING, KernelLoggerInfo.cantCreatePasswordFile,
+ localPasswordFile.toString());
+ // if we can't make sure it's our file, don't write it
+ return;
+ }
+
+ /*
+ * XXX - There's a security hole here.
+ * Between the time the file is created and the permissions
+ * are changed to prevent others from opening it, someone
+ * else could open it and wait for the data to be written.
+ * Java needs the ability to create a file that's readable
+ * only by the owner; coming in JDK 7.
+ *
+ * The setReadable(false, false) call will fail on Windows.
+ * we ignore the failures on all platforms - this is a best
+ * effort. The above calls ensured that the file is our
+ * file, so the following is the best we can do on all
+ * operating systems.
+ */
+ localPasswordFile.setWritable(false, false); // take from all
+ localPasswordFile.setWritable(true, true); // owner only
+ localPasswordFile.setReadable(false, false); // take from all
+ localPasswordFile.setReadable(true, true); // owner only
+
+ w = new PrintWriter(localPasswordFile);
+ w.println(password);
+ } catch (IOException ex) {
+ // ignore errors
+ logger.log(Level.FINE, "Exception writing local password file", ex);
+ } finally {
+ if (w != null)
+ w.close();
+ }
+ }
+
+ /**
+ * Is the given password the local password?
+ */
+ public boolean isLocalPassword(String p) {
+ return password != null && password.equals(p);
+ }
+
+ /**
+ * Get the local password.
+ */
+ public String getLocalPassword() {
+ return password;
+ }
+
+ /**
+ * Convert the byte array to a hex string.
+ */
+ private static String toHex(byte[] b) {
+ char[] bc = new char[b.length * 2];
+ for (int i = 0, j = 0; i < b.length; i++) {
+ byte bb = b[i];
+ bc[j++] = hex[(bb >> 4) & 0xF];
+ bc[j++] = hex[bb & 0xF];
+ }
+ return new String(bc);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/LocalStrings.properties b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/LocalStrings.properties
new file mode 100644
index 0000000..c6e4abd
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/LocalStrings.properties
@@ -0,0 +1,235 @@
+#
+# Copyright (c) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+
+adapter.param.decode=Cannot decode parameter {0} = {1}
+adapter.param.missing={0} command requires the {1} parameter : {2}
+adapter.param.missing.passwordfile={0} command requires the passwordfile parameter containing {1} entry.
+adapter.param.missing.nodesc={0} command requires the {1} parameter
+adapter.exception=Exception in command execution : {0}
+adapter.command.notfound=Command {0} not found. \nCheck the entry of command name. This command may be provided by a package that is not installed.
+adapter.command.notcreated=Implementation for the command {0} exists in the system,\nbut it has some errors, check server.log for details
+adapter.command.noscope=Implementation for the command {0} exists in the system,\nbut it has no @Scoped annotation
+adapter.command.hasparams=Implementation for the command {0} exists in the system,\nbut it''s a singleton that also has parameters
+adapter.command.nocommand=No command was specified.
+adapter.wrongprivacy=Command {0} does not have {1} visibility.
+adapter.nodesc=No description provided
+adapter.panic=Wrong request landed in AdminAdapter {0}
+adapter.auth.userpassword=Invalid user name or password
+adapter.auth.notOnInstance=Configuration access to an instance is not allowed; please connect to the domain admin server instead to make configuration changes
+adapter.auth.remoteReqSecAdminOff=Remote configuration is currently disabled
+adapter.command.unacceptableValue=Invalid parameter: {0}. Its value is {1} but it isn''t one of these acceptable values: {2}
+adapter.usage=Usage:
+list.containers.command=List all known application containers
+list.containers.listapps=Applications deployed
+list.containers.nocontainer=No container currently configured
+
+lock.timeout=Command timed out. Unable to acquire a lock to access the domain. Another command acquired exclusive access to the domain on {0}. Retry the command at a later time.
+lock.timeoutunavailable=<<Date is unavailable>>
+lock.notacquired=The command was blocked. The domain was suspended by a user on {0}.
+lock.reason=Reason:
+
+
+stop.domain.command=Stop a running domain
+stop.domain.notDas=stop-domain only works with domains, this is a {0}
+
+restart.server.internalError=Internal Error: {0}
+restart.server.badNumModules=There should be only 1 primordial module but {0} primordial modules were found.
+restart.server.failure=Got an exception trying to restart: {0}
+restart.server.init=Server restart initiated
+restart.server.noStartupInfo=Unable to restart. Neither CLI or non-CLI startup info was found. \
+Here is what we were looking for:\n{0}\n{1}
+restart.server.asadminError=Error in Asadmin. These 3 arguments must be present on the server's \
+original command line:\n-asadmin-classpath\n-asadmin-classname\n-asadmin-args\nCould not restart.
+restart.server.nonAsadminError=Internal Error in ASMain. These 3 arguments were not set:\n\
+-startup-classpath\n-startup-classname\n-startup-args\nCould not restart.
+
+
+restart.domain.command=Restart a running domain
+restart.server.jvmError=Error running java process: {0}
+
+version.command=Returns the version of the application server
+locations.command=Returns the root and domain locations of the application server
+get.restart.required.command=Returns the "restart required" flag
+
+list.modules.command=List all the modules known to the module subsystem
+
+container=Container
+status=Status
+started=Started
+notstarted=Not Started
+connector=Connector
+implementation=Implementation
+contractprovider=ContractProvider
+
+create.profiler=Creates the profiler element. A server instance is tied to a particular profiler, by the profiler element in the Java configuration. Changing a profiler requires you to restart the server.
+create.profiler.classpath=Java classpath string that specifies the classes needed by the profiler.
+create.profiler.enabled=Profiler is enabled by default.
+create.profiler.nativelibrarypath=This path is automatically constructed to be a concatenation of the Application Serverm installation relative path for its native shared libraries, standard JRE native library path, the shell environment setting (LD_LIBRARY_PATH on UNIX) and any path that may be specified in the profile element.
+create.profiler.name=Name of the profiler.
+create.profiler.properties=Name/value pairs of provider specific attributes.
+create.profiler.target=This option specifies the target on which you are creating a profiler.
+create.profiler.usagetext=create-profiler\n\t[--classpath <classpath>] [--enabled[=<enabled(default:true)>]]\n\t[--nativelibrarypath <nativelibrarypath>]\n\t[--property (name=value)[:name=value]*]\n\t[--target <target(default:server)>] [-?|--help[=<help(default:false)>]]\n\tprofiler_name
+delete.profiler=The delete-profiler command deletes the profiler element you specify. A server instance is tied to a particular profiler by the profiler element in the Java configuration. Changing a profiler requires you to restart the server.
+delete.profiler.target=This option specifies the target profiler element which you are deleting.
+#Error Messages
+CouldNotCreateParamTokenizer=Could not create ParamTokenizer object.
+UnclosedString=Unclosed string value.
+NothingToList=Nothing to list.
+FileNotFound=The system cannot find the path specified: {0}
+
+
+ping.connection.pool.pool_name=Name of the JDBC Connection Pool to be pinged.
+ping.connection.pool.success=Ping JDBC Connection Pool for {0} is Successful.
+ping.connection.pool.fail=Ping JDBC Connection Pool for {0} is Failed.
+
+commandrunner.operand.required=Operand required.
+admin.param.missing={0} command requires the {1} parameter : {2}.
+admin.param.missing.nodesc={0} command requires the {1} parameter.
+admin.param.missing.nofound=Cannot find {1} in {0} command model, file a bug
+
+admin.set.invalid.attribute=Invalid attribute {0}
+admin.set.invalid.attributename=Invalid attribute name {0}
+admin.set.reject.keychange=Cannot change a primary key\nChange of {0}
+admin.set.configuration.notfound=No configuration found for {0}
+admin.set.attribute.change.failure=Could not change the attributes: {0}
+admin.set.delete.property.failure=Could not delete the property: {0}
+admin.set.deprecated=Warning: The attribute {0} is deprecated.
+admin.set.elementdeprecated=Warning: The element {0} is deprecated.
+admin.set.badelement=Cannot change the element: {0}
+admin.set.invalid.namevalue=Invalid name value pair {0}. Missing expected equal sign.
+admin.set.invalid.logservice.command=For setting log levels/attributes use set-log-levels/set-log-attributes command.
+admin.get.invalid.logservice.command=For getting log levels/attributes use list-log-levels/list-log-attributes command.
+admin.set.invalid.target=Unable to extract replication target from {0}
+admin.set.invalid.appname=Unable to extract application name from {0}
+admin.set.DomNotConfigBean=Internal error: Expected an object of type Dom ({0}) to be also a ConfigBean but it is not"
+admin.get.path.notfound=Dotted name path {0} not found.
+admin.get.no.monitoring=Monitoring facility not installed
+admin.get.monitoring.nodoubledot=Doubled dots are not allowed.
+admin.get.monitoring.invalidpattern=Illegal Match pattern: {0}
+admin.get.monitoring.invalidtarget=The specified target, {0}, is not a valid server''s name.
+admin.get.monitoring.unknown=Unknown Error: {0}
+admin.get.monitoring.empty=No monitoring data is available.
+admin.get.monitoring.remote.error=Error while trying get details from these instance(s): {0}
+create.system.properties=adds or updates one or more system properties of the domain, configuration, cluster, or server instance
+create.system.properties.name_value=The name value pairs (separated by the ':' character) of the system properties to add to the specified target. If any of the system properties were previously defined, it will be updated with the newly specified value.
+create.system.properties.usagetext=create-system-properties\n\t[--target <target(default:server)>] [-?|--help[=<help(default:false)>]]\n\t(name=value)[:name=value]*
+create.system.properties.existsAlready=System property {0} already exists.
+create.system.properties.failed=System property {0} creation failed.
+create.system.properties.success=System property {0} created successfully.
+delete.system.property=removes one system property of the domain, configuration, cluster, or server instance, at a time
+delete.system.property.property_name=The name of the system property to remove.
+delete.system.property.doesNotExist=System property {0} does not exist.
+delete.system.property.success=Deletion of system property {0} executed successfully.
+delete.system.property.failed=Deletion of system property {0} failed.
+list.system.properties=lists the system properties of the domain, configuration, cluster, or server instance
+list.system.properties.success=Command list-system-properties executed successfully.
+list.system.properties.fail=Command list-system-properties failed.
+invalid.target.sys.props=Invalid target:{0}. Valid targets types are domain, config, cluster, default server, clustered instance, stand alone instance.
+no.such.property=System Property named {0} does not exist at the given target {1}
+delete.sysprops.ok=System Property named {0} deleted from given target {1}. Make sure you check its references.
+list.ok=The target {0} contains following {1} system properties
+cant.delete.referenced.property=System Property {0} is referenced by {1} in the configuration. Please remove the references first.
+
+uptime=Returns how long the server has been running.
+uptime.command=Returns how long the server has been running.
+uptime.output.terse=Up {0}
+
+create.audit.module.duplicatefound=AuditModule named {0} exists. Cannot add duplicate AuditModule.
+create.audit.module.fail=Creation of AuditModule {0} failed
+create.audit.module.success=Creation of AuditModule {0} completed successfully
+list.audit.module.success=Command list-audit-modules executed successfully
+delete.audit.module.notfound=Specified Audit Module {0} not found
+delete.audit.module.fail=Deletion of Audit Module {0} failed
+delete.audit.module.success=Deletion of Audit Module {0} completed successfully
+
+create.message.security.provider.duplicatefound=Message security provider named {0} exists. Cannot add duplicate.
+create.message.security.provider.fail=Creation of message security provider named {0} failed.
+create.message.security.provider.success=Creation of message security provider named {0} completed successfully.
+
+delete.message.security.provider.confignotfound= A Message security config does not exist for the layer {0}
+delete.message.security.provider.fail=Deletion of message security provider named {0} failed
+delete.message.security.provider.success=Deletion of message security provider {0} completed successfully
+
+list.message.security.provider.success=list-message-security-providers successful
+
+set.usagetext=set [-?|--help[=<help(default:false)>]]\n\t(dotted-attribute-name=value)+
+version={0}
+version.verbose={0}, JRE version {1}
+
+
+#### Command Replication related stuff
+commandrunner.clusterexecutor.instantiationfailure=Unable to initialize specified executor class {0}: {1}
+commandrunner.executor.invalidtarget=Unable to find a valid target with name {0}
+commandrunner.executor.invalidtargettype=Target {0} is not a supported type. Command {1} supports these types of targets only: {2}
+commandrunner.executor.instanceopnotallowed=The {0} command is not allowed on target {1} because it is part of cluster {2}
+commandrunner.executor.supplementalcmdfailed=A supplemental command failed; cannot proceed further
+commandrunner.executor.errorwhilereplication=An error occurred during replication
+commandrunner.executor.errorinprepare=The command {0} cannot be completed because the preparation for the command failed indicating potential issues: {1}
+commandrunner.errCreDir=Could not create the directory {0}; no further information is available.
+commandrunner.executor.das.unallowed=Not authorized to execute command {0} on DAS
+commandrunner.executor.targettype.unallowed=Target type is not allowed on single instance command {0}
+commandrunner.noauth=User is not authorized for this command
+commandrunner.errAuth=Error during authorization
+commandrunner.executor.instance=Executing command {0} on instance
+commandrunner.unacceptableBV=Parameters for command {0} violate the following constraints:
+# This message one item in a list of reasons. The list is started with the message with key "commandrunner.unacceptableBV"
+commandrunner.unacceptableBV.reason=violation reason [ {0} ] on parameter [ {1} ]
+
+dynamicreconfiguration.diagnostics.devmode=The GlassFish environment does not have any clusters or instances present; Dynamic reconfiguration is turned off
+dynamicreconfiguration.diagnostics.delegatedcommand=This command is a delegated command. Dynamic reconfiguration will be bypassed
+dynamicreconfiguration.diagnostics.injectiondone=Parameter mapping, validation, injection completed successfully; Starting paramater injection
+dynamicreconfiguration.diagnostics.target=@ExecuteOn parsing and default settings done; Current target is {0}
+dynamicreconfiguration.diagnostics.runtimeTypes=RuntimeTypes are: {0}
+dynamicreconfiguration,diagnostics.targetTypes=TargetTypes are: {0}
+dynamicreconfiguration.diagnostics.replicationvalidationdone=All @ExecuteOn attribute and type validation completed successfully. Starting replication stages
+dynamicreconfiguration.diagnostics.prepareunodable=Command execution stage 1 : Calling prepare for undoable command {0}
+dynamicreconfiguration.diagnostics.presupplemental=Command execution stage 2 : Call pre supplemental commands for {0}
+dynamicreconfiguration.diagnostics.maincommand=Command execution stage 3 : Calling main command implementation for {0}
+dynamicreconfiguration.diagnostics.postsupplemental=Command execution stage 4 : Call post supplemental commands for {0}
+dynamicreconfiguration.diagnostics.afterreplsupplemental=Command execution stage 5 : Call post-replication supplemental commands for {0}
+dynamicreconfiguration.diagnostics.startreplication=Command execution stages completed on DAS; Starting replication on remote instances
+dynamicreconfiguration.diagnostics.undo=Command execution failed; calling undo() for command {0}
+dynamicreconfiguration.diagnostics.supplementalexec=Executing supplemental command {0}
+
+
+############ RuntimeInfo
+runtime.info.debug=JPDA Debugging is {0}
+interceptor.objectName.wrongservernames=This mbean call does not support multiple target instances
+interceptor.objectName.wrongobjectname=This mbean call is not supported for objectname {0}
+
+admin.adapter.unkAuth=Unknown admin access {0} returned; expected one of {1}
+
+job.cannot.be.null=Job cannot be null
+job.id.in.use=Job id is already in use
+removed.expired.job=Removed expired job {0}
+cleaning.jobs=Cleaning jobs
+cleaning.job=Cleaning job {0}
+managedJobConfig.change=ManagedJobConfig {0} was changed by {1}
+error.cleaning.jobs=Error while cleaning jobs {0}
+scheduling.cleanup=Scheduling cleanup
+jobcleanup.service.init=Initializing Job Cleanup service
+init.managed.config.bean=Initializing ManagedJobConfig bean
+error.persisting.job=Error when persisting job {0} {1}
+error.initializing.persistence.service=Error initializing Job Persistence service {0}
+error.reading.completed.jobs=Error reading completed jobs {0}
+error.initializing.job.manager.service=Error initializing Job Manager service {0}
+error.purging.completed.job=Error purging completed jobs {0} {1}
+error.reading.jobs.xml.file=Error reading jobs.xml file {0}
+
+checkpointhelper.wrongheader=Error reading checkpoint. Wrong header.
+checkpointhelper.cannotlocatecommand=Can not load checkpoint. Can not locate command {0}.
+checkpointhelper.wrongfileextension=Wrong checkpoint file extension {0}.
+checkpointhelepr.wrongfilename=Wrong checkpoint filename format: {0}.
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/LocationsCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/LocationsCommand.java
new file mode 100644
index 0000000..734796a
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/LocationsCommand.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.universal.process.ProcessUtils;
+import org.glassfish.api.ActionReport.MessagePart;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandLock;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+
+import javax.inject.Singleton;
+import org.glassfish.server.ServerEnvironmentImpl;
+import com.sun.enterprise.glassfish.bootstrap.StartupContextUtil;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import org.glassfish.api.admin.*;
+import org.glassfish.internal.config.UnprocessedConfigListener;
+
+/**
+ * Locations command to indicate where this server is installed.
+ * @author Jerome Dochez
+ */
+@Service(name="__locations")
+@Singleton
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("locations.command")
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="locations",
+ description="Location",
+ useForAuthorization=true)
+})
+public class LocationsCommand implements AdminCommand {
+
+ @Inject
+ ServerEnvironmentImpl env;
+
+ @Inject
+ private UnprocessedConfigListener ucl;
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ ActionReport report = context.getActionReport();
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ report.setMessage(env.getInstanceRoot().getAbsolutePath().replace('\\', '/'));
+ MessagePart mp = report.getTopMessagePart();
+ mp.addProperty("Base-Root", StartupContextUtil.getInstallRoot(env.getStartupContext()).getAbsolutePath());
+ mp.addProperty("Domain-Root", env.getDomainRoot().getAbsolutePath());
+ mp.addProperty("Instance-Root", env.getInstanceRoot().getAbsolutePath());
+ mp.addProperty("Config-Dir", env.getConfigDirPath().getAbsolutePath());
+ mp.addProperty("Uptime", ""+getUptime());
+ mp.addProperty("Pid", ""+ProcessUtils.getPid());
+ mp.addProperty("Restart-Required", ""+ucl.serverRequiresRestart());
+ }
+
+ private long getUptime() {
+ RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
+ long totalTime_ms = -1;
+
+ if (mxbean != null)
+ totalTime_ms = mxbean.getUptime();
+
+ if (totalTime_ms <= 0) {
+ long start = env.getStartupContext().getCreationTime();
+ totalTime_ms = System.currentTimeMillis() - start;
+ }
+ return totalTime_ms;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/MbeanService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/MbeanService.java
new file mode 100755
index 0000000..c756daf
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/MbeanService.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.management.InstanceNotFoundException;
+
+import org.glassfish.api.StartupRunLevel;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.config.support.PropertyResolver;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.internal.api.Globals;
+import org.glassfish.internal.api.Target;
+import org.jvnet.hk2.annotations.Service;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.Server;
+
+@Service
+@RunLevel(mode=RunLevel.RUNLEVEL_MODE_NON_VALIDATING, value=StartupRunLevel.VAL)
+public class MbeanService {
+
+ @Inject
+ private Domain domain;
+
+ @Inject
+ private Target tgt;
+
+ private static ServiceLocator habitat = Globals.getDefaultHabitat();
+
+ @Inject
+ private ServerEnvironment env;
+
+
+ public static MbeanService getInstance() {
+ if (habitat == null)
+ return null;
+ return habitat.getService(MbeanService.class);
+ }
+
+ public String getHost(String instance) throws InstanceNotFoundException {
+ Server s = domain.getServerNamed(instance);
+ if (s == null)
+ throw new InstanceNotFoundException();
+ return s.getAdminHost();
+ }
+
+ public String getJMXPort(String instance) throws InstanceNotFoundException {
+ Server s = domain.getServerNamed(instance);
+ if (s == null)
+ throw new InstanceNotFoundException();
+ return new PropertyResolver(domain, instance).getPropertyValue("JMX_SYSTEM_CONNECTOR_PORT");
+ }
+
+ public boolean isDas() {
+ return tgt.isThisDAS();
+ }
+
+ public boolean isValidServer(String name) {
+ Server s = null;
+ try {
+ s = domain.getServerNamed(name);
+ } catch (Throwable t) {
+ return false;
+ }
+ return (s == null) ? false : true;
+ }
+
+ public List<String> getAllInstances() {
+ return convertList(tgt.getAllInstances());
+ }
+
+ public List<String> getInstances(String name) {
+ return convertList(tgt.getInstances(name));
+ }
+
+ private List<String> convertList(List<Server> servers) {
+ List<String> serverStrings = new ArrayList<String>();
+ for (Server svr : servers)
+ serverStrings.add(svr.getName());
+ return serverStrings;
+ }
+
+ public boolean isInstance(String name) {
+ return env.getInstanceName().equals(name);
+ }
+
+ /**
+ * Returns if the SystemJMXConnector is secure or not
+ *
+ * @param instance
+ * @return
+ */
+ public boolean isSecureJMX(String instance) {
+ String isSecure = "false";
+ if (domain.getServerNamed(instance) != null) {
+ if (domain.getServerNamed(instance).getConfig().getAdminService().getSystemJmxConnector() != null) {
+ isSecure = domain.getServerNamed(instance).getConfig().getAdminService().getSystemJmxConnector().getSecurityEnabled();
+ }
+ }
+ return Boolean.parseBoolean(isSecure);
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/MonitoringReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/MonitoringReporter.java
new file mode 100644
index 0000000..9ca1e7c
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/MonitoringReporter.java
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.admin.util.ClusterOperationUtil;
+import com.sun.enterprise.config.serverbeans.*;
+import com.sun.enterprise.util.StringUtils;
+import org.glassfish.api.admin.AccessRequired.AccessCheck;
+import static com.sun.enterprise.util.StringUtils.ok;
+import com.sun.enterprise.v3.common.ActionReporter;
+import com.sun.enterprise.v3.common.PlainTextActionReporter;
+import com.sun.enterprise.v3.common.PropsFileActionReporter;
+import java.lang.reflect.Proxy;
+import java.util.*;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.*;
+import org.glassfish.external.statistics.Statistic;
+import org.glassfish.external.statistics.Stats;
+import org.glassfish.external.statistics.impl.StatisticImpl;
+import org.glassfish.internal.api.*;
+import org.jvnet.hk2.annotations.Optional;
+
+import org.jvnet.hk2.annotations.Service;
+import static org.glassfish.api.ActionReport.ExitCode.FAILURE;
+import static org.glassfish.api.ActionReport.ExitCode.SUCCESS;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.flashlight.MonitoringRuntimeDataRegistry;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceLocator;
+
+import javax.inject.Inject;
+
+import static com.sun.enterprise.util.SystemPropertyConstants.MONDOT;
+import static com.sun.enterprise.util.SystemPropertyConstants.SLASH;
+import java.io.ByteArrayOutputStream;
+import java.util.Map;
+
+/**
+ *
+ * @author Byron Nevins First breathed life on November 6, 2010 The copyright
+ * says 1997 because one method in here has code moved verbatim from
+ * GetCommand.java which started life in 1997
+ *
+ * Note: what do you suppose is the worst possible name for a TreeNode class?
+ * Correct! TreeNode! Clashing names is why we have to explicitly use this
+ * ghastly name: org.glassfish.flashlight.datatree.TreeNode all over the
+ * place...
+ */
+@Service(name = "MonitoringReporter")
+@PerLookup
+@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+public class MonitoringReporter extends V2DottedNameSupport {
+
+ private final TreeMap nodeTreeToProcess = new TreeMap(); // used for get
+ private List<org.glassfish.flashlight.datatree.TreeNode> nodeListToProcess =
+ new ArrayList<org.glassfish.flashlight.datatree.TreeNode>(); // used for list
+
+ public enum OutputType {
+
+ GET, LIST
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("\nPattern=[").append(pattern).append("]").append('\n');
+
+ if (!targets.isEmpty()) {
+ for (Server server : targets) {
+ if (server != null)
+ sb.append("Server=[").append(server.getName()).append("]").append('\n');
+ }
+ }
+ else
+ sb.append("No Targets");
+
+ return sb.toString();
+ }
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////////// The API Methods ///////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+ public void prepareGet(AdminCommandContext c, String arg, Boolean data) {
+ aggregateDataOnly = data;
+ prepare(c, arg, OutputType.GET);
+ }
+
+ public Collection<? extends AccessCheck> getAccessChecksForGet() {
+ final Collection<AccessCheck> accessChecks = new ArrayList<AccessCheck>();
+ for (Object obj : nodeTreeToProcess.keySet()) {
+ final String name = obj.toString().replace('.', '/');
+ accessChecks.add(new AccessCheck(sanitizeResourceName(name), "read"));
+ }
+ return accessChecks;
+ }
+
+ public Collection<? extends AccessCheck> getAccessChecksForList() {
+ final Collection<AccessCheck> accessChecks = new ArrayList<AccessCheck>();
+ for (org.glassfish.flashlight.datatree.TreeNode tn1 : nodeListToProcess) {
+ /*
+ * doList discards nodes that do not have children, but we
+ * include them here in building the access checks
+ * because the user needs read access to the node
+ * in order to find out that it does or does not have children.
+ */
+ String name = tn1.getCompletePathName().replace('.', '/');
+ accessChecks.add(new AccessCheck(sanitizeResourceName(name), "read"));
+ }
+ return accessChecks;
+ }
+
+ private String sanitizeResourceName(final String resourceName) {
+ return StringUtils.replace(resourceName, "[", "_ARRAY_");
+ }
+ public void prepareList(AdminCommandContext c, String arg) {
+ prepare(c, arg, OutputType.LIST);
+ }
+
+ public void execute() {
+ // TODO remove? make it an exception???
+ if (hasError())
+ return;
+
+ runLocally();
+ runRemotely();
+ if (targetIsMultiInstanceCluster && isInstanceRunning()) {
+ runAggregate();
+ }
+
+ }
+
+ private boolean isInstanceRunning() {
+ boolean rs = false;
+ int num = 0;
+
+ List<Server> allServers = targetService.getAllInstances();
+ for (Server server : allServers) {
+ if (server.isRunning()) {
+ num++;
+ }
+ }
+ if (num >= 2)
+ rs = true;
+
+ return rs;
+ }
+
+ private void runAggregate() {
+ List<String> list = getOutputLines();
+ ActionReport aggregateReporter = null;
+ if (aggregateDataOnly) {
+ plainReporter = new PlainTextActionReporter();
+ aggregateReporter = plainReporter.addSubActionsReport();
+ }
+ else
+ aggregateReporter = reporter.addSubActionsReport();
+ setClusterInfo(aggregateReporter, list);
+ if (aggregateDataOnly) {
+ reporter = plainReporter;
+ context.setActionReport(plainReporter);
+ }
+ }
+
+ private List<String> getOutputLines() {
+ List<String> list = null;
+ try {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ reporter.writeReport(os);
+ String outputMessage = os.toString();
+ String lines[] = outputMessage.split("\\n");
+ list = Arrays.asList(lines);
+ }
+ catch (Exception e) {
+ }
+ return list;
+ }
+
+ private ArrayList<String> getKeyValuePair(String str, String instanceName) {
+ ArrayList<String> list = new ArrayList<String>(2);
+ String key = null;
+ String value = null;
+ if (str != null) {
+ key = str.substring(0, str.lastIndexOf("="));
+ key = (key.substring(instanceName.length() + 1)).trim();
+ value = (str.substring(str.lastIndexOf("=") + 1, str.length())).trim();
+ }
+ list.add(0, key);
+ list.add(1, value);
+ return list;
+ }
+
+ private void setClusterInfo(ActionReport aggregateReporter, List<String> list) {
+ List<HashMap> data = new ArrayList<HashMap>(targets.size());
+ int i;
+ for (i = 0; i < targets.size(); i++) {
+ data.add(new HashMap<String, String>());
+ }
+ HashMap<String, String> clusterInfo = new HashMap<String, String>();
+ int instanceCount = 0;
+ for (Server server : targets) {
+ String instanceName = server.getName();
+ Map<String, String> instanceMap = data.get(instanceCount);
+ String key = null;
+ for (String str : list) {
+ if (str.contains(instanceName) && str.contains("-count =")) {
+ ArrayList<String> kv = getKeyValuePair(str, instanceName);
+ key = (String) kv.get(0);
+ instanceMap.put((String) kv.get(0), kv.get(1));
+ }
+ if (key != null) {
+ String desc = key.substring(0, key.indexOf("-count")) + "-description";
+ if (str.contains(desc)) {
+ ArrayList<String> kv = getKeyValuePair(str, instanceName);
+ clusterInfo.put((String) kv.get(0), kv.get(1));
+ }
+ String lastSampleTime = key.substring(0, key.indexOf("-count")) + "-lastsampletime";
+ if (str.contains(lastSampleTime)) {
+ ArrayList<String> kv = getKeyValuePair(str, instanceName);
+ clusterInfo.put(instanceName + "." + (String) kv.get(0), kv.get(1));
+ key = null;
+ }
+ }
+ }
+ instanceCount++;
+ }
+
+ List<Server> allServers = targetService.getAllInstances();
+ String instanceListStr = "";
+ i = 0;
+ for (Server server : allServers) {
+ if (server.isRunning()) {
+ if (i == 0)
+ instanceListStr = server.getName();
+ else
+ instanceListStr = instanceListStr + ", " + server.getName();
+ i++;
+ }
+ }
+ aggregateReporter.appendMessage("\nComputed Aggregate Data for " + i + " instances: " + instanceListStr + " in cluster " + targetName + " :\n");
+ boolean noData = true;
+ HashMap<String, String> h = data.get(0);
+ Iterator it = h.keySet().iterator();
+
+ while (it.hasNext()) {
+ int total = 0, max = 0, min = 0, index = 0;
+ float avg = 0;
+ int[] values = new int[data.size()];
+ boolean flag = false;
+ String s = (String) it.next();
+ for (HashMap hm : data) {
+ String tmp = (String) hm.get(s);
+ // if tmp is null then the string is not available in all the instances, so not required to add this in the cluster information
+ if (tmp == null) {
+ flag = true;
+ break;
+ }
+ else {
+ int count = Integer.parseInt(tmp);
+ values[index++] = count;
+ total = total + count;
+ }
+ }
+ if (!flag) {
+ noData = false;
+ Arrays.sort(values);
+ min = values[0];
+ max = values[values.length - 1];
+ avg = (float) total / (float) data.size();
+ String descKey = s.substring(0, s.length() - 5) + "description";
+ aggregateReporter.appendMessage(targetName + "." + s + "-total = " + total + "\n");
+ aggregateReporter.appendMessage(targetName + "." + s + "-avg = " + avg + "\n");
+ aggregateReporter.appendMessage(targetName + "." + s + "-max = " + max + "\n");
+ aggregateReporter.appendMessage(targetName + "." + s + "-min = " + min + "\n");
+ aggregateReporter.appendMessage(targetName + "." + descKey + " = " + clusterInfo.get(descKey) + "\n");
+ String lastSampleTimeKey = s.substring(0, s.length() - 5) + "lastsampletime";
+ long sampletime = getLastSampleTime(clusterInfo, lastSampleTimeKey, data.size());
+ aggregateReporter.appendMessage(targetName + "." + lastSampleTimeKey + " = " + sampletime + "\n");
+ }
+ }
+ if (noData) {
+ aggregateReporter.appendMessage("No aggregated cluster data to report\n");
+ }
+ }
+
+ private long getLastSampleTime(HashMap<String, String> clusterInfo, String lastSampleTimeKey, int numofInstances) {
+ long[] values = new long[numofInstances];
+ int index = 0;
+ for (Map.Entry e : clusterInfo.entrySet()) {
+ String key = (String) e.getKey();
+ String value = (String) e.getValue();
+ if (key.contains(lastSampleTimeKey)) {
+ values[index++] = Long.parseLong(value);
+ }
+ }
+ Arrays.sort(values);
+ return values[values.length - 1];
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////////// ALL PRIVATE BELOW ///////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+ private void prepare(AdminCommandContext c, String arg, OutputType type) {
+ outputType = type;
+ context = c;
+ prepareReporter();
+ // DAS runs the show on this command. If we are running in an
+ // instance -- that means we should call runLocally() AND it also
+ // means that the pattern is already perfect!
+
+ if (isDas())
+ prepareDas(arg);
+ else
+ prepareInstance(arg);
+
+ prepareNodesToProcess();
+ }
+
+ /**
+ * The stock ActionReport we get is too inefficient. Replace it with
+ * PlainText note that we might be called with HTML or XML or JSON or
+ * others!
+ */
+ private void prepareReporter() {
+ reporter = (ActionReporter) context.getActionReport();
+
+ if (reporter instanceof PlainTextActionReporter) {
+ // already setup correctly - don't change it!!
+ plainReporter = (PlainTextActionReporter) reporter;
+ }
+ else if (reporter instanceof PropsFileActionReporter) {
+ plainReporter = new PlainTextActionReporter();
+ reporter = plainReporter;
+ context.setActionReport(plainReporter);
+ }
+ else {
+ plainReporter = null;
+ }
+ }
+
+ private void prepareDas(String arg) {
+ // TODO throw an exception if any errors????
+ try {
+ setSuccess();
+ userarg = arg;
+
+ if (!validate()) {
+ return;
+ }
+ }
+ catch (Exception e) {
+ setError(Strings.get("admin.get.monitoring.unknown", e.getMessage()));
+ reporter.setFailureCause(e);
+ }
+ }
+
+ private void prepareInstance(String arg) {
+ // TODO throw an exception if any errors!
+ pattern = arg;
+ }
+
+ // mostly just copied over from old "get" implementation
+ // That's why it is excruciatingly unreadable...
+ private void prepareNodesToProcess() {
+
+ // don't run if this is DAS **and** DAS is not in the server list.
+ // otherwise we are in an instance and definitely want to run!
+ if (isDas() && !dasIsInList())
+ return;
+
+ // say the pattern is "something" -->
+ // we want "server.something" for DAS and "i1.server.something" for i1
+ // Yes -- this is difficult to get perfect!!! What if user entered
+ //"server.something"?
+
+ String localPattern = prependServerDot(pattern);
+ org.glassfish.flashlight.datatree.TreeNode tn = datareg.get(serverEnv.getInstanceName());
+
+ if (tn == null) {
+ return;
+ }
+
+ List<org.glassfish.flashlight.datatree.TreeNode> ltn = tn.getNodes(localPattern);
+ boolean singleStat = false;
+
+ if (ltn == null || ltn.isEmpty()) {
+ org.glassfish.flashlight.datatree.TreeNode parent = tn.getPossibleParentNode(localPattern);
+
+ if (parent != null) {
+ ltn = new ArrayList<org.glassfish.flashlight.datatree.TreeNode>(1);
+ ltn.add(parent);
+ singleStat = true;
+ }
+ }
+
+ if (!singleStat) {
+ localPattern = null; // signal to method call below. localPattern was already used above...
+ }
+
+ if (outputType == OutputType.GET) {
+ prepareNodeTreeToProcess(localPattern, ltn);
+ }
+ else if (outputType == OutputType.LIST) {
+ nodeListToProcess = ltn;
+ }
+ }
+
+ private void runLocally() {
+
+ // don't run if this is DAS **and** DAS is not in the server list.
+ // otherwise we are in an instance and definitely want to run!
+ if (isDas() && !dasIsInList()) {
+ return;
+ }
+
+ if (outputType == OutputType.GET) {
+ doGet();
+ }
+ else if (outputType == OutputType.LIST) {
+ doList();
+ }
+
+ if (plainReporter != null) {
+ plainReporter.appendMessage(cliOutput.toString());
+ }
+ }
+
+ private void prepareNodeTreeToProcess(final String pattern, final List<org.glassfish.flashlight.datatree.TreeNode> ltn) {
+ for (org.glassfish.flashlight.datatree.TreeNode tn1 : sortTreeNodesByCompletePathName(ltn)) {
+ if (!tn1.hasChildNodes()) {
+ insertNameValuePairs(nodeTreeToProcess, tn1, pattern);
+ }
+ }
+ }
+
+ // Byron Nevins -- copied from original implementation
+ private void doGet() {
+
+ ActionReport.MessagePart topPart = reporter.getTopMessagePart();
+ Iterator it = nodeTreeToProcess.keySet().iterator();
+
+ while (it.hasNext()) {
+ Object obj = it.next();
+ String line = obj.toString();
+ line = line.replace(SLASH, "/") + " = " + nodeTreeToProcess.get(obj);
+
+ if (plainReporter != null)
+ cliOutput.append(line).append('\n');
+ else {
+ ActionReport.MessagePart part = topPart.addChild();
+ part.setMessage(line);
+ }
+ }
+ setSuccess();
+ }
+
+ private void doList() {
+ // list means only print things that have children. Don't print the children.
+ ActionReport.MessagePart topPart = reporter.getTopMessagePart();
+
+ for (org.glassfish.flashlight.datatree.TreeNode tn1 : nodeListToProcess) {
+ if (tn1.hasChildNodes()) {
+ String line = tn1.getCompletePathName();
+
+ if (plainReporter != null)
+ cliOutput.append(line).append('\n');
+ else {
+ ActionReport.MessagePart part = topPart.addChild();
+ part.setMessage(line);
+ }
+ }
+ }
+ setSuccess();
+ }
+
+ /**
+ * This can be a bit confusing. It is sort of like a recursive call.
+ * GetCommand will be called on the instance. BUT -- the pattern arg will
+ * just have the actual pattern -- the target name will NOT be in there! So
+ * "runLocally" will be called on the instance. this method will ONLY run on
+ * DAS (guaranteed!)
+ */
+ private void runRemotely() {
+ if (!isDas())
+ return;
+
+ List<Server> remoteServers = getRemoteServers();
+
+ if (remoteServers.isEmpty())
+ return;
+
+ try {
+ ParameterMap paramMap = new ParameterMap();
+ paramMap.set("monitor", "true");
+ paramMap.set("DEFAULT", pattern);
+ ClusterOperationUtil.replicateCommand("get", FailurePolicy.Error, FailurePolicy.Warn,
+ FailurePolicy.Ignore, remoteServers, context, paramMap, habitat);
+ }
+ catch (Exception ex) {
+ setError(Strings.get("admin.get.monitoring.remote.error", getNames(remoteServers)));
+ }
+ }
+
+ private String prependServerDot(String s) {
+ // note -- we are now running in either DAS or an instance and we are going to gather up
+ // data ONLY for this server. I.e. the DAS dispatching has already happened.
+ // we really need this pattern to start with the instance-name (DAS's instance-name is "server"
+
+ // Issue#15054
+ // this is pretty intricate but this is what we want to happen for these samples:
+ // asadmin get -m network.thread-pool.totalexecutedtasks-count ==> ERROR no target
+ // asadmin get -m server.network.thread-pool.totalexecutedtasks-count ==> OK, return DAS's data
+ // asadmin get -m *.network.thread-pool.totalexecutedtasks-count ==> OK return DAS and instances' data
+ // asadmin get -m i1.network.thread-pool.totalexecutedtasks-count ==> OK return data for i1
+
+ final String namedot = serverEnv.getInstanceName() + ".";
+
+ if (s.startsWith(namedot))
+ return s;
+
+ return namedot + s;
+ }
+
+ private boolean validate() {
+ if (datareg == null) {
+ setError(Strings.get("admin.get.no.monitoring"));
+ return false;
+ }
+
+ if (!initPatternAndTargets())
+ return false;
+
+ return true;
+ }
+
+ /*
+ * VERY VERY complicated to get this right!
+ */
+ private boolean initPatternAndTargets() {
+ Server das = domain.getServerNamed("server");
+
+ // no DAS in here!
+ List<Server> allServers = targetService.getAllInstances();
+
+ allServers.add(das);
+
+ // 0 decode special things
+ // \\ == literal backslash and \ is escaping next char
+ userarg = handleEscapes(userarg); // too complicated to do in-line
+
+ // MONDOT, SLASH should be replaced with literals
+ userarg = userarg.replace(MONDOT, ".").replace(SLASH, "/");
+
+ // double star makes no sense. The loop gets rid of "***", "****", etc.
+ while (userarg.indexOf("**") >= 0)
+ userarg = userarg.replace("**", "*");
+
+ // 1. nothing
+ // 2. *
+ // 3. *. --> which is a weird input but let's accept it anyway!
+ // 4 . --> very weird but we'll take it
+ if (!ok(userarg)
+ || userarg.equals("*")
+ || userarg.equals(".")
+ || userarg.equals("*.")) {
+ // By definition this means ALL servers and ALL data
+ targets = allServers;
+ pattern = "*";
+ return true;
+ }
+
+ // 5. *..
+ // 6. *.<something>
+ if (userarg.startsWith("*.")) {
+ targets = allServers;
+
+ // note: it can NOT be just "*." -- there is something at posn #2 !!
+ pattern = userarg.substring(2);
+
+ // "*.." is an error
+ if (pattern.startsWith(".")) {
+ String specificError = Strings.get("admin.get.monitoring.nodoubledot");
+ setError(Strings.get("admin.get.monitoring.invalidpattern", specificError));
+ return false;
+ }
+ return true;
+ }
+
+ // 7. See 14685 for an example --> "*jsp*"
+ // 16313 for another example
+ if (userarg.startsWith("*")) {
+ targets = allServers;
+ pattern = userarg;
+ return true;
+ }
+
+ // Another example:
+ // servername*something*
+ // IT 14778
+ // note we will NOT support serv*something getting resolved to server*something
+ // that's too crazy. They have to enter a reasonable name
+
+ // we are looking for, e.g. instance1*foo.goo*
+ // target is instance1 pattern is *foo.goo*
+ // instance1.something is handled below
+ String re = "[^\\.]+\\*.*";
+
+ if (userarg.matches(re)) {
+ int index = userarg.indexOf("*");
+
+ if (index < 0) { // can't happen!!
+ setError(Strings.get("admin.get.monitoring.invalidtarget", userarg));
+ return false;
+ }
+ targetName = userarg.substring(0, index);
+ pattern = userarg.substring(index);
+ }
+
+ if (targetName == null) {
+ int index = userarg.indexOf(".");
+
+ if (index >= 0) {
+ targetName = userarg.substring(0, index);
+
+ if (userarg.length() == index + 1) {
+ // 8. <servername>.
+ pattern = "*";
+ }
+ else
+ // 9. <servername>.<pattern>
+ pattern = userarg.substring(index + 1);
+ }
+ else {
+ // no dots in userarg
+ // 10. <servername>
+ targetName = userarg;
+ pattern = "*";
+ }
+ }
+
+ // note that "server" is hard-coded everywhere in GF code. We're stuck with it!!
+
+ if (targetName.equals("server") || targetName.equals("server-config")) {
+ targets.add(das);
+ return true;
+ }
+
+ // targetName is either 1 instance or a cluster or garbage!
+ targets = targetService.getInstances(targetName);
+
+ if (targets.isEmpty()) {
+ setError(Strings.get("admin.get.monitoring.invalidtarget", userarg));
+ return false;
+ }
+
+ if (targetService.isCluster(targetName) && targets.size() > 1)
+ targetIsMultiInstanceCluster = true;
+
+ return true;
+ }
+
+ private void insertNameValuePairs(
+ TreeMap map, org.glassfish.flashlight.datatree.TreeNode tn1, String exactMatch) {
+ String name = tn1.getCompletePathName();
+ Object value = tn1.getValue();
+ if (tn1.getParent() != null) {
+ map.put(tn1.getParent().getCompletePathName() + DOTTED_NAME,
+ tn1.getParent().getCompletePathName());
+ }
+ if (value instanceof Stats) {
+ for (Statistic s : ((Stats) value).getStatistics()) {
+ String statisticName = s.getName();
+ if (statisticName != null) {
+ statisticName = s.getName().toLowerCase(Locale.getDefault());
+ }
+ addStatisticInfo(s, name + "." + statisticName, map);
+ }
+ }
+ else if (value instanceof Statistic) {
+ addStatisticInfo(value, name, map);
+ }
+ else {
+ map.put(name, value);
+ }
+
+ // IT 8985 bnevins
+ // Hack to get single stats. The code above above would take a lot of
+ // time to unwind. For development speed we just remove unwanted items
+ // after the fact...
+ if (exactMatch != null) {
+ NameValue nv = getIgnoreBackslash(map, exactMatch);
+ map.clear();
+
+ if (nv != null) {
+ map.put(nv.name, nv.value);
+ }
+ }
+ }
+
+ /*
+ * bnevins, 1-11-11
+ * Note that we can not GUESS where to put the backslash into 'pattern'.
+ * If so -- we could simply add it into pattern and do a get on the HashMap.
+ * Instead we have to get each and every key in the map, remove backslashes
+ * and compare.
+ */
+ private NameValue getIgnoreBackslash(TreeMap map, String pattern) {
+
+ if (pattern == null)
+ return null;
+
+ Object match = map.get(pattern);
+
+ if (match != null)
+ return new NameValue(pattern, match);
+
+ pattern = pattern.replace("\\", "");
+ match = map.get(pattern);
+
+ if (match != null)
+ return new NameValue(pattern, match);
+
+ // No easy match...
+
+ Set<Map.Entry> elems = map.entrySet();
+
+ for (Map.Entry elem : elems) {
+ String key = elem.getKey().toString();
+
+ if (!ok(key))
+ continue;
+
+ String name = key.replace("\\", "");
+
+ if (pattern.equals(name))
+ return new NameValue(key, elem.getValue());
+ }
+ return null;
+ }
+
+ private void addStatisticInfo(Object value, String name, TreeMap map) {
+ Map<String, Object> statsMap;
+ // Most likely we will get the proxy of the StatisticImpl,
+ // reconvert that so you can access getStatisticAsMap method
+ if (Proxy.isProxyClass(value.getClass())) {
+ statsMap = ((StatisticImpl) Proxy.getInvocationHandler(value)).getStaticAsMap();
+ }
+ else {
+ statsMap = ((StatisticImpl) value).getStaticAsMap();
+ }
+ for (Map.Entry<String,Object> entry : statsMap.entrySet()) {
+ map.put(name + "-" + entry.getKey(), entry.getValue());
+ }
+ }
+
+ private void setError(String msg) {
+ reporter.setActionExitCode(FAILURE);
+ appendStatusMessage(msg);
+ clear();
+ }
+
+ private void setSuccess() {
+ reporter.setActionExitCode(SUCCESS);
+ }
+
+ private void appendStatusMessage(String newMessage) {
+ if (plainReporter != null)
+ cliOutput.append(newMessage).append('\n');
+ else {
+ String oldMessage = reporter.getMessage();
+
+ if (oldMessage == null)
+ reporter.setMessage(newMessage);
+ else
+ reporter.appendMessage("\n" + newMessage);
+ }
+ }
+
+ private boolean hasError() {
+ //return reporter.hasFailures();
+ return reporter.getActionExitCode() == FAILURE;
+ }
+
+ private void clear() {
+ targets = Collections.emptyList();
+ pattern = "";
+ }
+
+ private List<Server> getRemoteServers() {
+ // only call on DAS !!!
+ if (!isDas())
+ throw new RuntimeException("Internal Error"); // todo?
+
+ List<Server> notdas = new ArrayList<Server>(targets.size());
+ String dasName = serverEnv.getInstanceName();
+
+ for (Server server : targets) {
+ if (!dasName.equals(server.getName()))
+ notdas.add(server);
+ }
+
+ return notdas;
+ }
+
+ private boolean dasIsInList() {
+ return getRemoteServers().size() != targets.size();
+ }
+
+ private String getNames(List<Server> list) {
+ boolean first = true;
+ StringBuilder sb = new StringBuilder();
+
+ for (Server server : list) {
+ if (first)
+ first = false;
+ else
+ sb.append(", ");
+
+ sb.append(server.getName());
+ }
+ return sb.toString();
+ }
+
+ private static String handleEscapes(String s) {
+ // replace double backslash with backslash
+ // simply remove single backslash
+ // there is probably a much better, and very very complicated way to do
+ // this with regexp. I don't care - it is only done once for each time
+ // a user runs a get -m comand.
+ final String UNLIKELY_STRING = "___~~~~$$$$___";
+ return s.replace("\\\\", UNLIKELY_STRING).replace("\\", "").replace(UNLIKELY_STRING, "\\");
+ }
+
+ private boolean isDas() {
+ return serverEnv.isDas();
+ }
+
+ /*
+ * Surprise! The variables are down here. All the variables are private.
+ * That means they are an implementation detail and are hidden at the bottom
+ * of the file.
+ */
+ List<Server> targets = new ArrayList<Server>();
+ private PlainTextActionReporter plainReporter;
+ private ActionReporter reporter;
+ private AdminCommandContext context;
+ private String pattern;
+ private String userarg;
+ @Inject
+ @Optional
+ private MonitoringRuntimeDataRegistry datareg;
+ @Inject
+ private Domain domain;
+ @Inject
+ private Target targetService;
+ @Inject
+ ServerEnvironment serverEnv;
+ @Inject
+ ServiceLocator habitat;
+ private OutputType outputType;
+ private final static String DOTTED_NAME = ".dotted-name";
+ private final StringBuilder cliOutput = new StringBuilder();
+ private boolean targetIsMultiInstanceCluster = false;
+ private String targetName;
+ private Boolean aggregateDataOnly = Boolean.FALSE;
+
+ private static class NameValue {
+
+ String name;
+ Object value;
+
+ private NameValue(String s, Object o) {
+ name = s;
+ value = o;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ObjectInputStreamForClassloader.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ObjectInputStreamForClassloader.java
new file mode 100644
index 0000000..d485750
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ObjectInputStreamForClassloader.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.util.Collection;
+
+/** ObjectInputStream implementation with possibility to provide primary class
+ * loader.
+ *
+ * @author martinmares
+ */
+public class ObjectInputStreamForClassloader extends ObjectInputStream {
+
+ private final Collection<ClassLoader> classLoaders;
+
+ public ObjectInputStreamForClassloader(InputStream in, Collection<ClassLoader> classLoaders)
+ throws IOException {
+ super(in);
+ this.classLoaders = classLoaders;
+ }
+
+ @Override
+ protected Class<?> resolveClass(ObjectStreamClass classDesc)
+ throws IOException, ClassNotFoundException {
+ for (ClassLoader cl : classLoaders) {
+ try {
+ Class<?> result = Class.forName(classDesc.getName(), false, cl);
+ return result;
+ } catch (ClassNotFoundException e) {
+ }
+ }
+ return super.resolveClass(classDesc);
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ObjectInputStreamWithServiceLocator.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ObjectInputStreamWithServiceLocator.java
new file mode 100644
index 0000000..1253030
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ObjectInputStreamWithServiceLocator.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.glassfish.hk2.api.ActiveDescriptor;
+import org.glassfish.hk2.api.Descriptor;
+import org.glassfish.hk2.api.Filter;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.jvnet.hk2.annotations.Service;
+
+import java.io.*;
+import java.lang.reflect.Array;
+import java.util.List;
+import org.glassfish.hk2.api.MultiException;
+
+/**
+ * This subclass of ObjectInputStream uses HK2 to lookup classes not resolved by
+ * default ClassLoader.
+ *
+ * @author Andriy Zhdanov
+ */
+
+@Service
+public class ObjectInputStreamWithServiceLocator extends ObjectInputStream {
+
+ private final ServiceLocator serviceLocator;
+
+ /**
+ * Loader must be non-null;
+ *
+ * @throws IOException on io error
+ * @throws StreamCorruptedException on a corrupted stream
+ */
+
+ public ObjectInputStreamWithServiceLocator(InputStream in, ServiceLocator serviceLocator)
+ throws IOException, StreamCorruptedException {
+
+ super(in);
+ if (serviceLocator == null) {
+ throw new IllegalArgumentException("Illegal null argument to ObjectInputStreamWithLoader");
+ }
+ this.serviceLocator = serviceLocator;
+ }
+
+ /**
+ * Use the given ClassLoader rather than using the system class
+ *
+ * @throws ClassNotFoundException if class can not be loaded
+ */
+ @Override
+ protected Class<?> resolveClass(ObjectStreamClass classDesc)
+ throws IOException, ClassNotFoundException {
+ try {
+ // Try superclass first
+ return super.resolveClass(classDesc);
+ } catch (ClassNotFoundException e) {
+ String cname = classDesc.getName();
+ if (cname.startsWith("[")) {
+ // An array
+ Class<?> component; // component class
+ int dcount; // dimension
+ for (dcount = 1; cname.charAt(dcount) == '['; dcount++) ;
+ if (cname.charAt(dcount) == 'L') {
+ component = loadClass(cname.substring(dcount + 1,
+ cname.length() - 1));
+ } else {
+ throw new ClassNotFoundException(cname);// malformed
+ }
+ int dim[] = new int[dcount];
+ for (int i = 0; i < dcount; i++) {
+ dim[i] = 0;
+ }
+ return Array.newInstance(component, dim).getClass();
+ } else {
+ return loadClass(cname);
+ }
+ }
+ }
+
+ private Class<?> loadClass(final String cname) throws ClassNotFoundException {
+ List<ActiveDescriptor<?>> descriptors;
+ // non-services are not known by HK2
+ if ("com.oracle.cloudlogic.accountmanager.cli.AccountAwareJobImpl".equals(cname)) {
+ descriptors = getDescriptors("com.oracle.cloudlogic.accountmanager.cli.AccountAwareJobCreator");
+ } else {
+ descriptors = getDescriptors(cname);
+ }
+ if (descriptors.size() > 0) {
+ try {
+ return descriptors.get(0).getLoader().loadClass(cname);
+ } catch (MultiException ex) {
+ throw ex;
+ }
+ } else {
+ throw new ClassNotFoundException(cname);
+ }
+ }
+
+ private List<ActiveDescriptor<?>> getDescriptors(final String cname) throws ClassNotFoundException {
+ return serviceLocator.getDescriptors(new Filter() {
+ @Override
+ public boolean matches(Descriptor d) {
+ return d.getImplementation().equals(cname);
+ }
+ });
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/PrivateAdminAdapter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/PrivateAdminAdapter.java
new file mode 100644
index 0000000..a210af3
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/PrivateAdminAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.glassfish.internal.api.Privacy;
+import org.glassfish.internal.api.Private;
+import org.glassfish.internal.api.Visibility;
+import org.glassfish.api.admin.AdminCommand;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Admin adapter for private glassfish commands.
+ *
+ * @author Jerome Dochez
+ */
+@Service
+public class PrivateAdminAdapter extends AdminAdapter {
+
+ public final static String VS_NAME="__private_asadmin";
+ public final static String PREFIX_URI = "/" + VS_NAME;
+
+ public PrivateAdminAdapter() {
+ super(Private.class);
+ }
+
+ protected boolean validatePrivacy(AdminCommand command) {
+ Visibility visibility = command.getClass().getAnnotation(Visibility.class);
+ return (visibility==null?false:visibility.value().equals(Private.class));
+ }
+
+ public String getContextRoot() {
+ return PREFIX_URI;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ProcessHttpCommandRequestException.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ProcessHttpCommandRequestException.java
new file mode 100644
index 0000000..3df9122
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/ProcessHttpCommandRequestException.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.glassfish.api.ActionReport;
+import org.glassfish.grizzly.http.util.HttpStatus;
+
+/** Inform, that HttpCommandExecution has problem. Must change status code.
+ *
+ * @author mmares
+ */
+public class ProcessHttpCommandRequestException extends Exception {
+
+ private ActionReport report;
+ private HttpStatus responseStatus = HttpStatus.OK_200;
+
+ /**
+ * Constructs an instance of
+ * <code>InvalidPreconditionException</code> with the specified detail
+ * message.
+ *
+ * @param report Report with result
+ */
+ public ProcessHttpCommandRequestException(ActionReport report) {
+ this(report, null);
+ }
+
+ /**
+ * Constructs an instance of
+ * <code>InvalidPreconditionException</code> with the specified detail
+ * message.
+ *
+ * @param responseStatus HttpResponse status code
+ */
+ public ProcessHttpCommandRequestException(HttpStatus responseStatus) {
+ this(null, responseStatus);
+ }
+
+ /**
+ * Constructs an instance of
+ * <code>InvalidPreconditionException</code> with the specified detail
+ * message.
+ *
+ * @param report Report with result
+ * @param responseStatus HttpResponse status code
+ */
+ public ProcessHttpCommandRequestException(ActionReport report, HttpStatus responseStatus) {
+ super();
+ this.report = report;
+ if (responseStatus != null) {
+ this.responseStatus = responseStatus;
+ }
+ }
+
+ public ActionReport getReport() {
+ return report;
+ }
+
+ public HttpStatus getResponseStatus() {
+ return responseStatus;
+ }
+
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/PublicAdminAdapter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/PublicAdminAdapter.java
new file mode 100644
index 0000000..090009c
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/PublicAdminAdapter.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.glassfish.internal.api.Visibility;
+import org.glassfish.internal.api.Public;
+import org.glassfish.api.admin.AdminCommand;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Adapter for public administrative commands.
+ *
+ * @author Jerome Dochez
+ */
+@Service
+public class PublicAdminAdapter extends AdminAdapter {
+
+ public final static String VS_NAME="__asadmin";
+ public final static String PREFIX_URI = "/" + VS_NAME;
+
+ public PublicAdminAdapter() {
+ super(Public.class);
+ }
+
+ public String getContextRoot() {
+ return PREFIX_URI;
+ }
+
+ protected boolean validatePrivacy(AdminCommand command) {
+ Visibility visibility = command.getClass().getAnnotation(Visibility.class);
+ return (visibility==null?true:visibility.value().equals(Public.class));
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/RestartDomainCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/RestartDomainCommand.java
new file mode 100644
index 0000000..c4d4d74
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/RestartDomainCommand.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.module.ModulesRegistry;
+import org.glassfish.api.Async;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import javax.inject.Inject;
+import org.jvnet.hk2.annotations.Service;
+
+import org.glassfish.hk2.api.PerLookup;
+
+
+/**
+ * For non-verbose mode:
+ * Stop this server, spawn a new JVM that will wait for this JVM to die. The new JVM then starts the server again.
+ *
+ * For verbose mode:
+ * We want the asadmin console itself to do the respawning -- so just return a 10 from
+ * System.exit(). This tells asadmin to restart.
+ *
+ * @author Byron Nevins
+ */
+@Service(name = "restart-domain")
+@PerLookup
+@Async
+@I18n("restart.domain.command")
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.POST,
+ path="restart-domain",
+ description="restart-domain")
+})
+@AccessRequired(resource="domain", action={"stop","start"})
+public class RestartDomainCommand extends RestartServer implements AdminCommand {
+
+ @Inject
+ ModulesRegistry registry;
+ // no default value! We use the Boolean as a tri-state.
+ @Param(name = "debug", optional = true)
+ private String debug;
+ @Inject
+ private ServerEnvironment env;
+
+ /** version which will use injection */
+ public RestartDomainCommand() {
+ }
+
+ /** version which will not use injection */
+ public RestartDomainCommand(final ModulesRegistry registryIn) {
+ registry = registryIn;
+ }
+
+ /**
+ * Restart of the application server :
+ *
+ * All running services are stopped.
+ * LookupManager is flushed.
+ *
+ * Client code that started us should notice the return value of 10 and restart us.
+ */
+ public void execute(AdminCommandContext context) {
+ setRegistry(registry);
+ setServerName(env.getInstanceRoot().getName());
+ if (debug != null)
+ setDebug(Boolean.parseBoolean(debug));
+
+ doExecute(context);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/RestartServer.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/RestartServer.java
new file mode 100644
index 0000000..1d037a0
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/RestartServer.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.universal.i18n.LocalStringsImpl;
+import com.sun.enterprise.universal.process.JavaClassRunner;
+import com.sun.enterprise.universal.process.ProcessUtils;
+import com.sun.enterprise.util.StringUtils;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.internal.api.Globals;
+import org.glassfish.embeddable.GlassFish;
+
+import java.io.*;
+import java.util.*;
+import java.util.logging.*;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+/**
+ * For non-verbose mode:
+ * Stop this server, spawn a new JVM that will wait for this JVM to die. The new JVM then starts the server again.
+ *
+ * For verbose mode:
+ * We want the asadmin console itself to do the respawning -- so just return a special int from
+ * System.exit(). This tells asadmin to restart.
+ *
+ * @author Byron Nevins
+ */
+public class RestartServer {
+ @Inject
+ private Provider<GlassFish> glassfishProvider;
+
+ protected final void setDebug(Boolean b) {
+ debug = b;
+ }
+
+ protected final void setRegistry(final ModulesRegistry registryIn) {
+ registry = registryIn;
+ }
+
+ protected final void setServerName(String serverNameIn) {
+ serverName = serverNameIn;
+ }
+
+ /**
+ * Restart of the application server :
+ *
+ * All running services are stopped.
+ * LookupManager is flushed.
+ *
+ * Client code that started us should notice the special return value and restart us.
+ */
+ protected final void doExecute(AdminCommandContext context) {
+ try {
+ // unfortunately we can't rely on constructors with HK2...
+ if (registry == null)
+ throw new NullPointerException(new LocalStringsImpl(getClass()).get("restart.server.internalError", "registry was not set"));
+
+ init(context);
+
+ // get the GlassFish object - we have to wait in case startup is still in progress
+ // This is a temporary work-around until HK2 supports waiting for the service to
+ // show up in the ServiceLocator.
+ GlassFish gfKernel = glassfishProvider.get();
+ while (gfKernel == null) {
+ Thread.sleep(1000);
+ gfKernel = glassfishProvider.get();
+ }
+
+ if (!verbose) {
+ // do it now while we still have the Logging service running...
+ reincarnate();
+ }
+ // else we just return a special int from System.exit()
+ gfKernel.stop();
+ }
+ catch (Exception e) {
+ context.getLogger().severe(strings.get("restart.server.failure", e));
+ }
+
+ int ret = RESTART_NORMAL;
+
+ if (debug != null)
+ ret = debug ? RESTART_DEBUG_ON : RESTART_DEBUG_OFF;
+
+ System.exit(ret);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ ///////// ALL PRIVATE BELOW ////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ private void init(AdminCommandContext context) throws IOException {
+ logger = context.getLogger();
+ props = Globals.get(StartupContext.class).getArguments();
+ verbose = Boolean.parseBoolean(props.getProperty("-verbose", "false"));
+ logger.info(strings.get("restart.server.init"));
+ }
+
+ private void reincarnate() {
+ try {
+ if (setupReincarnationWithAsadmin() || setupReincarnationWithOther())
+ doReincarnation();
+ else
+ logger.severe(strings.get("restart.server.noStartupInfo",
+ strings.get("restart.server.asadminError"),
+ strings.get("restart.server.nonAsadminError")));
+ }
+ catch (RDCException rdce) {
+ // already logged...
+ }
+ catch (Exception e) {
+ logger.severe(strings.get("restart.server.internalError", e));
+ }
+
+ }
+
+ private void doReincarnation() throws RDCException {
+ try {
+ // TODO JavaClassRunner is very simple and primitive.
+ // Feel free to beef it up...
+
+ String[] props = normalProps;
+
+ if (Boolean.parseBoolean(System.getenv("AS_SUPER_DEBUG")))
+ props = debuggerProps; // very very difficult to debug this stuff otherwise!
+
+ new JavaClassRunner(classpath, props, classname, args);
+ }
+ catch (Exception e) {
+ logger.severe(strings.get("restart.server.jvmError", e));
+ throw new RDCException();
+ }
+ }
+
+ private boolean setupReincarnationWithAsadmin() throws RDCException {
+ classpath = props.getProperty("-asadmin-classpath");
+ classname = props.getProperty("-asadmin-classname");
+ argsString = props.getProperty("-asadmin-args");
+
+ return verify("restart.server.asadminError");
+ }
+
+ private boolean setupReincarnationWithOther() throws RDCException {
+
+ classpath = props.getProperty("-startup-classpath");
+ classname = props.getProperty("-startup-classname");
+ argsString = props.getProperty("-startup-args");
+
+ return verify("restart.server.nonAsadminError");
+ }
+
+ private boolean verify(String errorStringKey) throws RDCException {
+ // Either asadmin or non-asadmin startup params have been set -- check them!
+ // THREE possible returns:
+ // 1) true
+ // 2) false
+ // 3) RDCException
+ if (classpath == null && classname == null && argsString == null) {
+ return false;
+ }
+
+ // now that at least one is set -- demand that ALL OF THEM be set...
+ if (!ok(classpath) || !ok(classname) || argsString == null) {
+ logger.severe(strings.get(errorStringKey));
+ throw new RDCException();
+ }
+
+ args = argsString.split(",,,");
+ handleDebug();
+ return true;
+ }
+
+ private void handleDebug() {
+ if (debug == null) // nothing to do!
+ return;
+
+ stripDebugFromArgs();
+ stripOperandFromArgs();
+ int oldlen = args.length;
+ int newlen = oldlen + 2;
+ String debugArg = "--debug=" + debug.toString();
+ String[] newArgs = new String[newlen];
+
+ // copy all but the last arg (domain-name)
+ System.arraycopy(args, 0, newArgs, 0, args.length);
+ newArgs[newlen - 2] = debugArg;
+ newArgs[newlen - 1] = serverName;
+ args = newArgs;
+ }
+
+ private void stripDebugFromArgs() {
+ // this is surprisingly complex!
+ // "--debug domain1" is one
+ // "--debug=true" is one
+ // "--debug false" is two
+ boolean twoArgs = false;
+ int indexOfDebug = -1;
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].startsWith("--debug=")) {
+ indexOfDebug = i;
+ break;
+ }
+ if (args[i].startsWith("--debug")) {
+ indexOfDebug = i;
+
+ // who knows what happens in CLI when the domain's name is "true" ?!?
+ // we could potentially be fooled by that one very unlikely scenario
+ if (args.length > i + 1) {// broken into two if's for readability...
+ if (args[i + 1].equals("true") || args[i + 1].equals("false")) {
+ twoArgs = true;
+ }
+ }
+ break;
+ }
+ }
+
+ if (indexOfDebug < 0)
+ return;
+
+ int oldlen = args.length;
+ int newlen = oldlen - 1;
+
+ if (twoArgs)
+ --newlen;
+
+ String[] newArgs = new String[newlen];
+ int ctr = 0;
+
+ for (int i = 0; i < oldlen; i++) {
+ if (i == indexOfDebug)
+ continue;
+ if (twoArgs && i == (indexOfDebug + 1))
+ continue;
+
+ newArgs[ctr++] = args[i];
+ }
+
+ args = newArgs;
+ }
+
+ private void stripOperandFromArgs() {
+ // remove the domain-name operand
+ // it may not be here!
+ if (args.length < 2 || !StringUtils.ok(serverName))
+ return;
+
+ int newlen = args.length - 1;
+
+ if (serverName.equals(args[newlen])) {
+ String[] newargs = new String[newlen];
+ System.arraycopy(args, 0, newargs, 0, newlen);
+ args = newargs;
+ }
+ }
+
+ private boolean ok(String s) {
+ return s != null && s.length() > 0;
+ }
+
+ // We use this simply to tell the difference between fatal errors and other
+ // non-fatal conditions.
+ private static class RDCException extends Exception {
+ }
+ ModulesRegistry registry;
+ private Boolean debug = null;
+ private Properties props;
+ private Logger logger;
+ private boolean verbose;
+ private String classpath;
+ private String classname;
+ private String argsString;
+ private String[] args;
+ private String serverName = "";
+ private static final LocalStringsImpl strings = new LocalStringsImpl(RestartServer.class);
+ ///////////// static variables ///////////////////
+ private static final String magicProperty = "-DAS_RESTART=" + ProcessUtils.getPid();
+ private static final String[] normalProps = {magicProperty};
+ private static final int RESTART_NORMAL = 10;
+ private static final int RESTART_DEBUG_ON = 11;
+ private static final int RESTART_DEBUG_OFF = 12;
+ private static final String[] debuggerProps = {
+ magicProperty,
+ "-Xdebug",
+ "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=1323"};
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/RuntimeInfo.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/RuntimeInfo.java
new file mode 100644
index 0000000..ad1b287
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/RuntimeInfo.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import java.io.*;
+import static com.sun.enterprise.util.StringUtils.ok;
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import java.util.Properties;
+import org.glassfish.internal.api.Globals;
+import static com.sun.enterprise.util.StringUtils.ok;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import com.sun.enterprise.util.OS;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.Param;
+import java.util.logging.Level;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.ManagementFactory;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import java.util.logging.Logger;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandLock;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.config.support.*;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.config.types.Property;
+import static org.glassfish.api.ActionReport.ExitCode.SUCCESS;
+
+/**
+ * https://glassfish.dev.java.net/issues/show_bug.cgi?id=12483
+ * @author Byron Nevins
+ * @author Ludovic Champenois
+ */
+@Service(name = "_get-runtime-info")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@ExecuteOn({RuntimeType.INSTANCE})
+@TargetType({CommandTarget.DAS, CommandTarget.STANDALONE_INSTANCE, CommandTarget.CLUSTERED_INSTANCE})
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="get-runtime-info",
+ description="Get Runtime Info")
+})
+@AccessRequired(resource="domain", action="read")
+public class RuntimeInfo implements AdminCommand {
+ public RuntimeInfo() {
+ }
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ report = context.getActionReport();
+ report.setActionExitCode(SUCCESS);
+ top = report.getTopMessagePart();
+ logger = context.getLogger();
+ javaEnabledOnCmd = Boolean.parseBoolean(ctx.getArguments().getProperty("-debug"));
+ javaConfig = config.getJavaConfig();
+ jpdaEnabled = javaEnabledOnCmd || Boolean.parseBoolean(javaConfig.getDebugEnabled());
+ int debugPort = parsePort(javaConfig.getDebugOptions());
+ top.addProperty("debug", Boolean.toString(jpdaEnabled));
+ top.addProperty("debugPort", Integer.toString(debugPort));
+ final OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
+
+ top.addProperty("os.arch", osBean.getArch());
+ top.addProperty("os.name", osBean.getName());
+ top.addProperty("os.version", osBean.getVersion());
+ top.addProperty("availableProcessorsCount", "" + osBean.getAvailableProcessors());
+
+ // getTotalPhysicalMemorySize is from com.sun.management.OperatingSystemMXBean and cannot easily access it via OSGi
+ // also if we are not on a sun jdk, we will not return this attribute.
+ if ( !OS.isAix()) {
+ try {
+ final Method jm = osBean.getClass().getMethod("getTotalPhysicalMemorySize");
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ if (!jm.isAccessible()) {
+ jm.setAccessible(true);
+ }
+ return null;
+ }
+ });
+
+ top.addProperty("totalPhysicalMemorySize", "" + jm.invoke(osBean));
+
+ }
+ catch (Exception ex) {
+ logger.log(Level.SEVERE, null, ex);
+ }
+
+ }
+ RuntimeMXBean rmxb = ManagementFactory.getRuntimeMXBean();
+ top.addProperty("startTimeMillis", "" + rmxb.getStartTime());
+ top.addProperty("pid", "" + rmxb.getName());
+ checkDtrace();
+ setDasName();
+ top.addProperty("java.vm.name", System.getProperty("java.vm.name"));
+ setRestartable();
+ reportMessage.append(Strings.get("runtime.info.debug", jpdaEnabled ? "enabled" : "not enabled"));
+ report.setMessage(reportMessage.toString());
+ }
+
+ private void checkDtrace() {
+ try {
+ Class.forName("com.sun.tracing.ProviderFactory");
+ top.addProperty("dtrace", "true");
+ }
+ catch (Exception ex) {
+ top.addProperty("dtrace", "false");
+ }
+ }
+
+ private void setDasName() {
+ try {
+ String name = env.getInstanceRoot().getName();
+ top.addProperty("domain_name", name);
+ }
+ catch (Exception ex) {
+ // ignore
+ }
+ }
+
+ /**
+ * March 11 2011 -- See JIRA 16197
+ * Say the user started the server with a passwordfile arg. After they started it
+ * they deleted the password file. If we don't do anything special restart-server
+ * will take down the server -- but it will not startup again. The user will have no clue why.
+ * We can NOT tell the user directly because the restart server command is asynchronous
+ * (@Async annotation).
+ * So -- this method was added as a pre-flight check. The client restart commands
+ * should run this command and check the restartable flag to make sure
+ * the restart doesn't fail because of a missing password file.
+ */
+ private void setRestartable() {
+ // false positive is MUCH better than false negative. Err on the side of
+ // trying to restart if in doubt. No harm can result from that.
+ restartable = true;
+ String passwordFile = null;
+
+ try {
+ Properties props = Globals.get(StartupContext.class).getArguments();
+ String argsString = props.getProperty("-asadmin-args");
+
+ if (ok(argsString) && argsString.indexOf("--passwordfile") >= 0) {
+ String[] args = argsString.split(",,,");
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("--passwordfile")) {
+ if ((i + 1) < args.length && ok(args[i + 1])) {
+ passwordFile = args[i + 1];
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (Exception e) {
+ // nothing to do, but I'll do this anyway because I'm paranoid
+ restartable = true;
+ }
+
+ if (ok(passwordFile)) {
+ // the --passwordfile is here -- so it had best point to a file that
+ // exists and can be read! In all other cases -- restartable is true
+ File pwf = new File(passwordFile);
+ restartable = pwf.canRead();
+ }
+ top.addProperty("restartable", Boolean.toString(restartable));
+ }
+
+ private int parsePort(String s) {
+ //"-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9009"
+ int port = -1;
+ String[] ss = s.split(",");
+
+ for (String sub : ss) {
+ if (sub.startsWith("address=")) {
+ try {
+ port = Integer.parseInt(sub.substring(8));
+ }
+ catch (Exception e) {
+ port = -1;
+ }
+ break;
+ }
+ }
+ return port;
+ }
+ @Inject
+ ServerEnvironment env;
+ @Inject
+ private StartupContext ctx;
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ private Config config;
+ @Param(name = "target", optional = true, defaultValue = SystemPropertyConstants.SERVER_NAME)
+ String target;
+ private boolean jpdaEnabled;
+ private boolean javaEnabledOnCmd;
+ private JavaConfig javaConfig;
+ private ActionReport report;
+ private ActionReport.MessagePart top;
+ private Logger logger;
+ private StringBuilder reportMessage = new StringBuilder();
+
+ private boolean restartable;
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/SetCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/SetCommand.java
new file mode 100644
index 0000000..2014362
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/SetCommand.java
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.admin.util.ClusterOperationUtil;
+import com.sun.enterprise.config.modularity.ConfigModularityUtils;
+import com.sun.enterprise.config.modularity.GetSetModularityHelper;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.Server;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+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.FailurePolicy;
+import org.glassfish.api.admin.ParameterMap;
+import org.glassfish.api.admin.RuntimeType;
+import org.glassfish.api.admin.config.LegacyConfigurationUpgrade;
+import org.glassfish.internal.api.Target;
+
+import org.jvnet.hk2.annotations.Optional;
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.jvnet.hk2.config.ConfigBean;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.ConfigModel;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.Dom;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+import org.jvnet.hk2.config.WriteableView;
+import org.jvnet.hk2.config.types.Property;
+import org.jvnet.tiger_types.Types;
+
+import javax.inject.Inject;
+import java.beans.PropertyVetoException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.logging.Logger;
+
+import org.glassfish.api.admin.AccessRequired.AccessCheck;
+import org.glassfish.api.admin.AdminCommandSecurity;
+
+/**
+ * User: Jerome Dochez
+ * Date: Jul 11, 2008
+ * Time: 4:39:05 AM
+ */
+@Service(name = "set")
+@ExecuteOn(RuntimeType.INSTANCE)
+@PerLookup
+@I18n("set")
+public class SetCommand extends V2DottedNameSupport implements AdminCommand, PostConstruct,
+ AdminCommandSecurity.AccessCheckProvider, AdminCommandSecurity.Preauthorization {
+
+ @Inject
+ ServiceLocator habitat;
+
+ @Inject
+ Domain domain;
+
+ @Inject
+ ConfigSupport config;
+
+ @Inject
+ Target targetService;
+ @Inject
+ @Optional
+ GetSetModularityHelper modularityHelper;
+
+ @Inject
+ ConfigModularityUtils utils;
+
+ @Param(primary = true, multiple = true)
+ String[] values;
+ final private static LocalStringManagerImpl localStrings =
+ new LocalStringManagerImpl(SetCommand.class);
+
+ private HashMap<String, Integer> targetLevel = null;
+
+ private final Collection<SetOperation> setOperations = new ArrayList<SetOperation>();
+
+ @Override
+ public void postConstruct() {
+ targetLevel = new HashMap<String, Integer>();
+ targetLevel.put("applications", 0);
+ targetLevel.put("system-applications", 0);
+ targetLevel.put("resources", 0);
+ targetLevel.put("configs", 3);
+ targetLevel.put("clusters", 3);
+ targetLevel.put("servers", 3);
+ targetLevel.put("nodes", 3);
+ }
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ for (String value : values) {
+
+ if (value.contains(".log-service")) {
+ fail(context, localStrings.getLocalString("admin.set.invalid.logservice.command", "For setting log levels/attributes use set-log-levels/set-log-attributes command."));
+ return false;
+ }
+
+ if (!prepare(context, value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Collection<? extends AccessCheck> getAccessChecks() {
+ final Collection<AccessCheck> accessChecks = new ArrayList<AccessCheck>();
+ for (SetOperation op : setOperations) {
+ accessChecks.add(new AccessCheck(op.getResourceName(), "update"));
+ }
+ return accessChecks;
+ }
+
+
+
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ for (SetOperation op : setOperations) {
+ if (!set(context, op)) {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Captures information about each set operation conveyed on a single
+ * command invocation.
+ */
+ private static class SetOperation {
+ private final String target;
+ private final String value;
+ private final String pattern;
+ private final boolean isProperty;
+ private final String attrName;
+
+ private SetOperation(final String target, final String value, final String pattern,
+ final String attrName, final boolean isProperty) {
+ this.target = target;
+ this.value = value;
+ this.pattern = pattern;
+ this.attrName = attrName;
+ this.isProperty = isProperty;
+ }
+
+ /**
+ * Returns the name of the resource being affected by this set operation.
+ * @return
+ */
+ private String getResourceName() {
+ StringBuilder dottedNameForResourceName = new StringBuilder();
+ if (isProperty) {
+ final int propertyLiteralIndex = pattern.indexOf("property.");
+ dottedNameForResourceName.append(pattern.substring(0, propertyLiteralIndex));
+ } else {
+ dottedNameForResourceName.append(pattern);
+ }
+ if ( ! dottedNameForResourceName.toString().startsWith("domain.")) {
+ dottedNameForResourceName.insert(0, "domain.");
+ }
+ return dottedNameForResourceName.toString().replace('.', '/');
+ }
+ }
+
+ /**
+ * Processes a single name/value pair just enough to figure out what kind
+ * of entity the target is (an element, an attribute, a property) and saves
+ * that information as a SetOperation instance.
+ *
+ * @param context admin command context
+ * @param nameval a single name/value pair from the command
+ * @return
+ */
+ private boolean prepare(AdminCommandContext context, String nameval) {
+ int i = nameval.indexOf('=');
+ if (i < 0) {
+ //ail(context, "Invalid attribute " + nameval);
+ fail(context, localStrings.getLocalString("admin.set.invalid.namevalue", "Invalid name value pair {0}. Missing expected equal sign.", nameval));
+ return false;
+ }
+ String target = nameval.substring(0, i);
+ String value = nameval.substring(i + 1);
+ // so far I assume we always want to change one attribute so I am removing the
+ // last element from the target pattern which is supposed to be the
+ // attribute name
+ int lastDotIndex = trueLastIndexOf(target, '.');
+ if (lastDotIndex == -1) {
+ // error.
+ //fail(context, "Invalid attribute name " + target);
+ fail(context, localStrings.getLocalString("admin.set.invalid.attributename", "Invalid attribute name {0}", target));
+ return false;
+ }
+ String attrName = target.substring(lastDotIndex + 1).replace("\\.", ".");
+ String pattern = target.substring(0, lastDotIndex);
+ if (attrName.replace('_', '-').equals("jndi-name")) {
+ //fail(context, "Cannot change a primary key\nChange of " + target + " is rejected.");
+ fail(context, localStrings.getLocalString("admin.set.reject.keychange", "Cannot change a primary key\nChange of {0}", target));
+ return false;
+ }
+ boolean isProperty = false;
+ if ("property".equals(pattern.substring(trueLastIndexOf(pattern, '.') + 1))) {
+ // we are looking for a property, let's look it it exists already...
+ pattern = target.replaceAll("\\\\\\.", "\\.");
+ isProperty = true;
+ }
+
+ setOperations.add(new SetOperation(target, value, pattern, attrName, isProperty));
+ return true;
+ }
+
+ private boolean set(AdminCommandContext context, SetOperation op) {
+
+ String pattern = op.pattern;
+ String value = op.value;
+ String target = op.target;
+ String attrName = op.attrName;
+ boolean isProperty = op.isProperty;
+
+ // now
+ // first let's get the parent for this pattern.
+ TreeNode[] parentNodes = getAliasedParent(domain, pattern);
+
+ // reset the pattern.
+ String prefix;
+ boolean lookAtSubNodes = true;
+ if (parentNodes[0].relativeName.length() == 0 ||
+ parentNodes[0].relativeName.equals("domain")) {
+ // handle the case where the pattern references an attribute of the top-level node
+ prefix = "";
+ // pattern is already set properly
+ lookAtSubNodes = false;
+ }
+ else if(!pattern.startsWith(parentNodes[0].relativeName)) {
+ prefix = pattern.substring(0, pattern.indexOf(parentNodes[0].relativeName));
+ pattern = parentNodes[0].relativeName;
+ }
+ else {
+ prefix = "";
+ pattern = parentNodes[0].relativeName;
+ }
+ String targetName = prefix + pattern;
+
+ if (modularityHelper != null) {
+ synchronized (utils) {
+ boolean oldv = utils.isCommandInvocation();
+ utils.setCommandInvocation(true);
+ modularityHelper.getLocationForDottedName(targetName);
+ utils.setCommandInvocation(oldv);
+ }
+ }
+
+ Map<Dom, String> matchingNodes;
+ boolean applyOverrideRules = false;
+ Map<Dom, String> dottedNames = new HashMap<Dom, String>();
+ if (lookAtSubNodes) {
+ for (TreeNode parentNode : parentNodes) {
+ dottedNames.putAll(getAllDottedNodes(parentNode.node));
+ }
+ matchingNodes = getMatchingNodes(dottedNames, pattern);
+ applyOverrideRules = true;
+ } else {
+ matchingNodes = new HashMap<Dom, String>();
+ for (TreeNode parentNode : parentNodes) {
+ matchingNodes.put(parentNode.node, pattern);
+ }
+ }
+
+ if (matchingNodes.isEmpty()) {
+ // it's possible they are trying to create a property object.. lets check this.
+ // strip out the property name
+ pattern = target.substring(0, trueLastIndexOf(target, '.'));
+ if (pattern.endsWith("property")) {
+ pattern = pattern.substring(0, trueLastIndexOf(pattern, '.'));
+ parentNodes = getAliasedParent(domain, pattern);
+ pattern = parentNodes[0].relativeName;
+ matchingNodes = getMatchingNodes(dottedNames, pattern);
+ if (matchingNodes.isEmpty()) {
+ //fail(context, "No configuration found for " + targetName);
+ fail(context, localStrings.getLocalString("admin.set.configuration.notfound", "No configuration found for {0}", targetName));
+ return false;
+ }
+ // need to find the right parent.
+ Dom parentNode = null;
+ for (Map.Entry<Dom, String> node : matchingNodes.entrySet()) {
+ if (node.getValue().equals(pattern)) {
+ parentNode = node.getKey();
+ }
+ }
+ if (parentNode == null) {
+ //fail(context, "No configuration found for " + targetName);
+ fail(context, localStrings.getLocalString("admin.set.configuration.notfound", "No configuration found for {0}", targetName));
+ return false;
+ }
+
+ if (value == null || value.length() == 0) {
+ // setting to the empty string means to remove the property, so don't create it
+ success(context, targetName, value);
+ return true;
+ }
+ // create and set the property
+ Map<String, String> attributes = new HashMap<String, String>();
+ attributes.put("value", value);
+ attributes.put("name", attrName);
+ try {
+ if ( ! (parentNode instanceof ConfigBean)) {
+ final ClassCastException cce = new ClassCastException(parentNode.getClass().getName());
+ fail(context, localStrings.getLocalString("admin.set.attribute.change.failure",
+ "Could not change the attributes: {0}",
+ cce.getMessage(), cce));
+ return false;
+ }
+ ConfigSupport.createAndSet((ConfigBean) parentNode, Property.class, attributes);
+ success(context, targetName, value);
+ runLegacyChecks(context);
+ if (targetService.isThisDAS() && !replicateSetCommand(context, targetName, value))
+ return false;
+ return true;
+ } catch (TransactionFailure transactionFailure) {
+ //fail(context, "Could not change the attributes: " +
+ // transactionFailure.getMessage(), transactionFailure);
+ fail(context, localStrings.getLocalString("admin.set.attribute.change.failure", "Could not change the attributes: {0}",
+ transactionFailure.getMessage()), transactionFailure);
+ return false;
+ }
+ }
+ }
+
+ Map<ConfigBean, Map<String, String>> changes = new HashMap<ConfigBean, Map<String, String>>();
+
+ boolean setElementSuccess = false;
+ boolean delPropertySuccess = false;
+ boolean delProperty = false;
+ Map<String, String> attrChanges = new HashMap<String, String>();
+ if (isProperty) {
+ attrName = "value";
+ if ((value == null) || (value.length() == 0)) {
+ delProperty = true;
+ }
+ attrChanges.put(attrName, value);
+ }
+
+ List<Map.Entry> mNodes = new ArrayList(matchingNodes.entrySet());
+ if (applyOverrideRules) {
+ mNodes = applyOverrideRules(mNodes);
+ }
+ for (Map.Entry<Dom, String> node : mNodes) {
+ final Dom targetNode = node.getKey();
+
+ for (String name : targetNode.model.getAttributeNames()) {
+ String finalDottedName = node.getValue() + "." + name;
+ if (matches(finalDottedName, pattern)) {
+ if (attrName.equals(name) ||
+ attrName.replace('_', '-').equals(name.replace('_', '-'))) {
+ if (isDeprecatedAttr(targetNode, name)) {
+ warning(context, localStrings.getLocalString("admin.set.deprecated",
+ "Warning: The attribute {0} is deprecated.", finalDottedName));
+ }
+
+ if (!isProperty) {
+ targetName = prefix + finalDottedName;
+
+ if (value != null && value.length() > 0) {
+ attrChanges.put(name, value);
+ } else {
+ attrChanges.put(name, null);
+ }
+ } else {
+ targetName = prefix + node.getValue();
+ }
+
+ if (delProperty) {
+ // delete property element
+ String str = node.getValue();
+ if (trueLastIndexOf(str, '.') != -1) {
+ str = str.substring(trueLastIndexOf(str, '.') + 1);
+ }
+ try {
+ if (str != null) {
+ ConfigSupport.deleteChild((ConfigBean) targetNode.parent(), (ConfigBean) targetNode);
+ delPropertySuccess = true;
+ }
+ } catch (IllegalArgumentException ie) {
+ fail(context, localStrings.getLocalString("admin.set.delete.property.failure", "Could not delete the property: {0}",
+ ie.getMessage()), ie);
+ return false;
+ } catch (TransactionFailure transactionFailure) {
+ fail(context, localStrings.getLocalString("admin.set.attribute.change.failure", "Could not change the attributes: {0}",
+ transactionFailure.getMessage()), transactionFailure);
+ return false;
+ }
+ } else {
+ changes.put((ConfigBean) node.getKey(), attrChanges);
+ }
+
+ }
+ }
+ }
+
+ for (String name : targetNode.model.getLeafElementNames()) {
+ String finalDottedName = node.getValue() + "." + name;
+ if (matches(finalDottedName, pattern)) {
+ if (attrName.equals(name) ||
+ attrName.replace('_', '-').equals(name.replace('_', '-'))) {
+ if (isDeprecatedAttr(targetNode, name)) {
+ warning(context, localStrings.getLocalString("admin.set.elementdeprecated",
+ "Warning: The element {0} is deprecated.", finalDottedName));
+ }
+ try {
+ setLeafElement((ConfigBean)targetNode, name, value);
+ } catch (TransactionFailure ex) {
+ fail(context, localStrings.getLocalString("admin.set.badelement", "Cannot change the element: {0}",
+ ex.getMessage()), ex);
+ return false;
+ }
+ setElementSuccess = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!changes.isEmpty()) {
+ try {
+ config.apply(changes);
+ success(context, targetName, value);
+ runLegacyChecks(context);
+ } catch (TransactionFailure transactionFailure) {
+ //fail(context, "Could not change the attributes: " +
+ // transactionFailure.getMessage(), transactionFailure);
+ fail(context, localStrings.getLocalString("admin.set.attribute.change.failure", "Could not change the attributes: {0}",
+ transactionFailure.getMessage()), transactionFailure);
+ return false;
+ }
+
+ } else if (delPropertySuccess || setElementSuccess) {
+ success(context, targetName, value);
+ } else {
+ fail(context, localStrings.getLocalString("admin.set.configuration.notfound", "No configuration found for {0}", targetName));
+ return false;
+ }
+ if (targetService.isThisDAS() && !replicateSetCommand(context, targetName, value))
+ return false;
+ return true;
+ }
+
+ public static void setLeafElement (
+ final ConfigBean node,
+ final String elementName,
+ final String values)
+ throws TransactionFailure {
+
+ ConfigBeanProxy readableView = node.getProxy(node.getProxyType());
+ ConfigSupport.apply(new SingleConfigCode<ConfigBeanProxy>() {
+
+ /**
+ * Runs the following command passing the configuration object. The code will be run
+ * within a transaction, returning true will commit the transaction, false will abort
+ * it.
+ *
+ * @param param is the configuration object protected by the transaction
+ * @return any object that should be returned from within the transaction code
+ * @throws java.beans.PropertyVetoException
+ * if the changes cannot be applied
+ * to the configuration
+ */
+ @Override
+ public Object run(ConfigBeanProxy param) throws PropertyVetoException, TransactionFailure {
+
+ WriteableView writeableParent = (WriteableView)Proxy.getInvocationHandler(param);
+
+ StringTokenizer st = new StringTokenizer(values, ",");
+ List<String> valList = new ArrayList<String>();
+ while (st.hasMoreTokens()) valList.add(st.nextToken());
+
+ ConfigBean bean = writeableParent.getMasterView();
+ for (Method m : writeableParent.getProxyType().getMethods()) {
+ // Check to see if the method is a setter for the element
+ // An element setter has to have the right name, take a single
+ // collection parameter that parameterized with the right type
+ Class argClasses[] = m.getParameterTypes();
+ Type argTypes[] = m.getGenericParameterTypes();
+ ConfigModel.Property prop = bean.model.toProperty(m);
+ if (prop == null ||
+ !prop.xmlName().equals(elementName) ||
+ argClasses.length != 1 ||
+ !Collection.class.isAssignableFrom(argClasses[0]) ||
+ argTypes.length != 1 ||
+ !(argTypes[0] instanceof ParameterizedType) ||
+ !Types.erasure(Types.getTypeArgument(argTypes[0], 0)).isAssignableFrom(values.getClass())) {
+ continue;
+ }
+ // we have the right method. Now call it
+ try {
+ m.invoke(writeableParent.getProxy(writeableParent.<ConfigBeanProxy>getProxyType()), valList);
+ } catch (IllegalAccessException e) {
+ throw new TransactionFailure("Exception while setting element", e);
+ } catch (InvocationTargetException e) {
+ throw new TransactionFailure("Exception while setting element", e);
+ }
+ return node;
+ }
+ throw new TransactionFailure("No method found for setting element");
+ }
+ }, readableView);
+ }
+
+ /*
+ * Determine whether this attribute is deprecated. This method
+ * stops looking after it finds the first method or field whose name matches
+ * the attribute name. So to make an attribute deprecated, all of the
+ * methods (set, get, etc.) must be marked as deprecated.
+ */
+ private boolean isDeprecatedAttr(Dom dom, String name) {
+ if (dom == null || dom.model == null || name == null) return false;
+ Class t = dom.getProxyType();
+ if (t == null) return false;
+ for (Method m : t.getDeclaredMethods()) {
+ ConfigModel.Property p = dom.model.toProperty(m);
+ if (p != null && name.equals(p.xmlName())) {
+ return m.isAnnotationPresent(Deprecated.class);
+ }
+ }
+ for (Field f : t.getDeclaredFields()) {
+ if (name.equals(dom.model.camelCaseToXML(f.getName()))) {
+ return f.isAnnotationPresent(Deprecated.class);
+ }
+ }
+ return false;
+ }
+
+ private String getElementFromString(String name, int index) {
+ StringTokenizer token = new StringTokenizer(name, ".");
+ String target = null;
+ for (int j = 0; j < index; j++) {
+ if (token.hasMoreTokens())
+ target = token.nextToken();
+ }
+ return target;
+ }
+
+ private boolean replicateSetCommand(AdminCommandContext context, String targetName, String value) {
+ // "domain." on the front of the attribute name is optional. So if it is
+ // there, strip it off.
+ List<Server> replicationInstances = null;
+ String tName;
+ if (targetName.startsWith("domain.")) {
+ tName = targetName.substring("domain.".length());
+ if (tName.indexOf('.') == -1) {
+ // This is a domain-level attribute, replicate to all instances
+ replicationInstances = targetService.getAllInstances();
+ }
+ }
+ else {
+ tName = targetName;
+ }
+ if (replicationInstances == null) {
+ int dotIdx = tName.indexOf('.');
+ String firstElementOfName = dotIdx != -1 ? tName.substring(0, dotIdx) : tName;
+ Integer targetElementLocation = targetLevel.get(firstElementOfName);
+ if (targetElementLocation == null)
+ targetElementLocation = 1;
+ if (targetElementLocation == 0) {
+ if ("resources".equals(firstElementOfName)) {
+ replicationInstances = targetService.getAllInstances();
+ }
+ if ("applications".equals(firstElementOfName)) {
+ String appName = getElementFromString(tName, 3);
+ if (appName == null) {
+ fail(context, localStrings.getLocalString("admin.set.invalid.appname",
+ "Unable to extract application name from {0}", targetName));
+ return false;
+ }
+ replicationInstances = targetService.getInstances(domain.getAllReferencedTargetsForApplication(appName));
+ }
+ } else {
+ String target = getElementFromString(tName, targetElementLocation);
+ if (target == null) {
+ fail(context, localStrings.getLocalString("admin.set.invalid.target",
+ "Unable to extract replication target from {0}", targetName));
+ return false;
+ }
+ replicationInstances = targetService.getInstances(target);
+ }
+ }
+
+ if (replicationInstances != null && !replicationInstances.isEmpty()) {
+ ParameterMap params = new ParameterMap();
+ params.set("DEFAULT", targetName + "=" + value);
+ ActionReport.ExitCode ret = ClusterOperationUtil.replicateCommand("set", FailurePolicy.Error,
+ FailurePolicy.Warn, FailurePolicy.Ignore, replicationInstances, context, params, habitat);
+ if (ret.equals(ActionReport.ExitCode.FAILURE))
+ return false;
+ }
+ return true;
+ }
+
+ private void runLegacyChecks(AdminCommandContext context) {
+ final Collection<LegacyConfigurationUpgrade> list = habitat.<LegacyConfigurationUpgrade>getAllServices(LegacyConfigurationUpgrade.class);
+ for (LegacyConfigurationUpgrade upgrade : list) {
+ upgrade.execute(context);
+ }
+ }
+
+ /**
+ * Find the rightmost unescaped occurrence of specified character in target
+ * string.
+ * <p/>
+ * XXX Doesn't correctly interpret escaped backslash characters, e.g. foo\\.bar
+ *
+ * @param target string to search
+ * @param ch a character
+ * @return index index of last unescaped occurrence of specified character
+ * or -1 if there are no unescaped occurrences of this character.
+ */
+ private static int trueLastIndexOf(String target, char ch) {
+ int i = target.lastIndexOf(ch);
+ while (i > 0) {
+ if (target.charAt(i - 1) == '\\') {
+ i = target.lastIndexOf(ch, i - 1);
+ } else {
+ break;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Indicate in the action report that the command failed.
+ */
+ private static void fail(AdminCommandContext context, String msg) {
+ fail(context, msg, null);
+ }
+
+ /**
+ * Indicate in the action report that the command failed.
+ */
+ private static void fail(AdminCommandContext context, String msg,
+ Exception ex) {
+ context.getActionReport().setActionExitCode(
+ ActionReport.ExitCode.FAILURE);
+ if (ex != null)
+ context.getActionReport().setFailureCause(ex);
+ context.getActionReport().setMessage(msg);
+ }
+
+ /**
+ * Indicate in the action report a warning message.
+ */
+ private void warning(AdminCommandContext context, String msg) {
+ ActionReport ar = context.getActionReport().addSubActionsReport();
+ ar.setActionExitCode(ActionReport.ExitCode.WARNING);
+ ar.setMessage(msg);
+ }
+
+ /**
+ * Indicate in the action report that the command succeeded and
+ * include the target property and it's value in the report
+ */
+ private void success(AdminCommandContext context, String target, String value) {
+ context.getActionReport().setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ ActionReport.MessagePart part = context.getActionReport().getTopMessagePart().addChild();
+ part.setChildrenType("DottedName");
+ part.setMessage(target + "=" + value);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/StopDomainCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/StopDomainCommand.java
new file mode 100644
index 0000000..70a38f7
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/StopDomainCommand.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import org.glassfish.api.Async;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import javax.inject.Inject;
+import org.jvnet.hk2.annotations.Service;
+
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceLocator;
+
+/**
+ * AdminCommand to stop the domain execution which mean shuting down the application
+ * server.
+ *
+ * @author Jerome Dochez
+ */
+@Service(name = "stop-domain")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@Async
+@I18n("stop.domain.command")
+@AccessRequired(resource="domain", action="stop")
+@ExecuteOn(RuntimeType.DAS)
+public class StopDomainCommand extends StopServer implements AdminCommand {
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(StopDomainCommand.class);
+ @Inject
+ ServiceLocator habitat;
+ @Inject
+ ServerEnvironment env;
+ @Param(optional = true, defaultValue = "true")
+ Boolean force;
+
+ /**
+ * Shutdown of the application server :
+ *
+ * All running services are stopped.
+ * LookupManager is flushed.
+ */
+ public void execute(AdminCommandContext context) {
+
+ if (!env.isDas()) {
+ // This command is asynchronous. We can't return anything so we just
+ // log the error and return
+ String msg = localStrings.getLocalString("stop.domain.notDas",
+ "stop-domain only works with domains, this is a {0}",
+ env.getRuntimeType().toString());
+
+ context.getLogger().warning(msg);
+ return;
+ }
+
+ doExecute(habitat, env, force);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/StopServer.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/StopServer.java
new file mode 100644
index 0000000..7efacde
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/StopServer.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.io.FileUtils;
+import java.io.File;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.embeddable.GlassFish;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.kernel.KernelLoggerInfo;
+
+/**
+ * A class to house identical code for stopping instances and DAS
+ * @author Byron Nevins
+ */
+public class StopServer {
+
+ /**
+ * Shutdown of the server :
+ *
+ * All running services are stopped.
+ * LookupManager is flushed.
+ */
+ protected final void doExecute(ServiceLocator habitat, ServerEnvironment env, boolean force) {
+ try {
+ KernelLoggerInfo.getLogger().info(KernelLoggerInfo.serverShutdownInit);
+ // Don't shutdown GlassFishRuntime, as that can bring the OSGi framework down which is wrong
+ // when we are embedded inside an existing runtime. So, just stop the glassfish instance that
+ // we are supposed to stop. Leave any cleanup to some other code.
+
+ // get the GlassFish object - we have to wait in case startup is still in progress
+ // This is a temporary work-around until HK2 supports waiting for the service to
+ // show up in the ServiceLocator.
+ GlassFish gfKernel = habitat.getService(GlassFish.class);
+ while (gfKernel == null) {
+ Thread.sleep(1000);
+ gfKernel = habitat.getService(GlassFish.class);
+ }
+ // gfKernel is absolutely positively for-sure not null.
+ gfKernel.stop();
+ }
+ catch (Throwable t) {
+ // ignore
+ }
+
+
+ if (force) {
+ System.exit(0);
+ }
+ else {
+ deletePidFile(env);
+ }
+ }
+
+ private final static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(StopServer.class);
+
+ /**
+ * It is **Essential** to delete this file! Other code will assume the server
+ * is running if it exists.
+ * Any old App is currently (10/10/10) allowed to add a shutdownhook with a System.exit()
+ * which is GUARANTEED to prevent the shutdown hook for deleting the pidfile to run.
+ * So -- we always do it BEFORE trying to exit.
+ */
+ private void deletePidFile(ServerEnvironment env) {
+ File pidFile = new File(env.getConfigDirPath(), "pid");
+
+ if (pidFile.isFile()) {
+ FileUtils.deleteFileNowOrLater(pidFile);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/Strings.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/Strings.java
new file mode 100644
index 0000000..9fc83fe
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/Strings.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.universal.i18n.LocalStringsImpl;
+
+/**
+ * Strings -- Get your Strings here.
+ * One file with Strings
+ * So one class for messing with them!
+ * Nothing in here is public protected. Only for use by this one java package.
+ * @author Byron Nevins
+ */
+
+final class Strings {
+ private Strings() {
+ // no instances allowed!
+ }
+
+ final static String get(String indexString) {
+ return strings.get(indexString);
+ }
+
+ final static String get(String indexString, Object... objects) {
+ return strings.get(indexString, objects);
+ }
+
+ final private static LocalStringsImpl strings = new LocalStringsImpl(Strings.class);
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/SupplementalCommandExecutorImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/SupplementalCommandExecutorImpl.java
new file mode 100755
index 0000000..bfe5479
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/SupplementalCommandExecutorImpl.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import org.glassfish.common.util.admin.CommandModelImpl;
+import org.glassfish.common.util.admin.MapInjectionResolver;
+import org.glassfish.hk2.api.ActiveDescriptor;
+import org.glassfish.hk2.api.ServiceHandle;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.api.ServerContext;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.component.*;
+import org.jvnet.hk2.config.InjectionManager;
+import org.jvnet.hk2.config.InjectionResolver;
+
+/**
+ * An executor that executes Supplemental commands means for current command
+ *
+ * @author Vijay Ramachandran
+ */
+@Service(name="SupplementalCommandExecutorImpl")
+public class SupplementalCommandExecutorImpl implements SupplementalCommandExecutor {
+
+ @Inject
+ private ServiceLocator habitat;
+
+ @Inject
+ private ServerEnvironment serverEnv;
+
+ @Inject
+ private ServerContext sc;
+
+ private static final Logger logger = KernelLoggerInfo.getLogger();
+
+ private static final LocalStringManagerImpl strings =
+ new LocalStringManagerImpl(SupplementalCommandExecutor.class);
+
+ private Map<String, List<ServiceHandle<?>>> supplementalCommandsMap = null;
+
+ public Collection<SupplementalCommand> listSuplementalCommands(String commandName) {
+ List<ServiceHandle<?>> supplementalList = getSupplementalCommandsList().get(commandName);
+ if (supplementalList == null) {
+ return Collections.emptyList();
+ }
+
+ Collection<SupplementalCommand> result = new ArrayList<SupplementalCommand>(supplementalList.size());
+ for (ServiceHandle<?> handle : supplementalList) {
+ AdminCommand cmdObject = (AdminCommand) handle.getService();
+ SupplementalCommand aCmd = new SupplementalCommandImpl(cmdObject);
+ if( (serverEnv.isDas() && aCmd.whereToRun().contains(RuntimeType.DAS)) ||
+ (serverEnv.isInstance() && aCmd.whereToRun().contains(RuntimeType.INSTANCE)) ) {
+ result.add(aCmd);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public ActionReport.ExitCode execute(Collection<SupplementalCommand> suplementals, Supplemental.Timing time,
+ AdminCommandContext context, ParameterMap parameters,
+ MultiMap<String, File> optionFileMap) {
+ //TODO : Use the executor service to parallelize this
+ ActionReport.ExitCode finalResult = ActionReport.ExitCode.SUCCESS;
+ if (suplementals == null) {
+ return finalResult;
+ }
+ for (SupplementalCommand aCmd : suplementals) {
+ if ((time.equals(Supplemental.Timing.Before) && aCmd.toBeExecutedBefore()) ||
+ (time.equals(Supplemental.Timing.After) && aCmd.toBeExecutedAfter()) ||
+ (time.equals(Supplemental.Timing.AfterReplication) && aCmd.toBeExecutedAfterReplication())) {
+ ActionReport.ExitCode result = FailurePolicy.applyFailurePolicy(aCmd.onFailure(),
+ inject(aCmd, getInjector(aCmd.getCommand(), parameters, optionFileMap, context),
+ context.getActionReport()));
+ if(!result.equals(ActionReport.ExitCode.SUCCESS)) {
+ if(finalResult.equals(ActionReport.ExitCode.SUCCESS))
+ finalResult = result;
+ continue;
+ }
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine(strings.getLocalString("dynamicreconfiguration.diagnostics.supplementalexec",
+ "Executing supplemental command " + aCmd.getClass().getCanonicalName()));
+ }
+ aCmd.execute(context);
+ if(context.getActionReport().hasFailures()) {
+ result = FailurePolicy.applyFailurePolicy(aCmd.onFailure(), ActionReport.ExitCode.FAILURE);
+ } else if(context.getActionReport().hasWarnings()) {
+ result = FailurePolicy.applyFailurePolicy(aCmd.onFailure(), ActionReport.ExitCode.WARNING);
+ }
+ if(!result.equals(ActionReport.ExitCode.SUCCESS)) {
+ if(finalResult.equals(ActionReport.ExitCode.SUCCESS))
+ finalResult = result;
+ }
+ }
+ }
+ return finalResult;
+ }
+
+ private static String getOne(String key, Map<String, List<String>> metadata) {
+ if (key == null || metadata == null) return null;
+ List<String> found = metadata.get(key);
+ if (found == null) return null;
+
+ if (found.isEmpty()) return null;
+
+ return found.get(0);
+ }
+
+ /**
+ * Get list of all supplemental commands, map it to various commands and cache this list
+ */
+ private synchronized Map<String, List<ServiceHandle<?>>> getSupplementalCommandsList() {
+
+ if (supplementalCommandsMap != null) return supplementalCommandsMap;
+
+ supplementalCommandsMap = new ConcurrentHashMap<String, List<ServiceHandle<?>>>();
+ List<ServiceHandle<Supplemental>> supplementals = habitat.getAllServiceHandles(Supplemental.class);
+ for (ServiceHandle<Supplemental> handle : supplementals) {
+ ActiveDescriptor<Supplemental> inh = handle.getActiveDescriptor();
+ String commandName = getOne("target", inh.getMetadata());
+ if(supplementalCommandsMap.containsKey(commandName)) {
+ supplementalCommandsMap.get(commandName).add(handle);
+ } else {
+ ArrayList<ServiceHandle<?>> inhList =
+ new ArrayList<ServiceHandle<?>>();
+ inhList.add(handle);
+ supplementalCommandsMap.put(commandName, inhList);
+ }
+ }
+ return supplementalCommandsMap;
+ }
+
+ private InjectionResolver<Param> getInjector(AdminCommand command, ParameterMap parameters, MultiMap<String, File> map, AdminCommandContext context) {
+ CommandModel model = command instanceof CommandModelProvider ?
+ ((CommandModelProvider)command).getModel() :
+ new CommandModelImpl(command.getClass());
+ MapInjectionResolver injector = new MapInjectionResolver(model, parameters, map);
+ injector.setContext(context);
+ return injector;
+ }
+
+ private ActionReport.ExitCode inject(SupplementalCommand cmd,
+ InjectionResolver<Param> injector, ActionReport subActionReport) {
+ ActionReport.ExitCode result = ActionReport.ExitCode.SUCCESS;
+ try {
+ new InjectionManager().inject(cmd.getCommand(), injector);
+ } catch (Exception e) {
+ result = ActionReport.ExitCode.FAILURE;
+ subActionReport.setActionExitCode(result);
+ subActionReport.setMessage(e.getMessage());
+ subActionReport.setFailureCause(e);
+ }
+ return result;
+ }
+
+ public class SupplementalCommandImpl implements SupplementalCommand {
+
+ private AdminCommand command;
+ private Supplemental.Timing timing;
+ private FailurePolicy failurePolicy;
+ private List<RuntimeType> whereToRun = new ArrayList<RuntimeType>(2);
+ private ProgressStatus progressStatus;
+ private Progress progressAnnotation;
+
+ private SupplementalCommandImpl(AdminCommand cmd) {
+ command = cmd;
+ Supplemental supAnn = cmd.getClass().getAnnotation(Supplemental.class);
+ timing = supAnn.on();
+ failurePolicy = supAnn.ifFailure();
+ ExecuteOn onAnn = cmd.getClass().getAnnotation(ExecuteOn.class);
+ progressAnnotation = cmd.getClass().getAnnotation(Progress.class);
+ if (onAnn == null) {
+ whereToRun.add(RuntimeType.DAS);
+ whereToRun.add(RuntimeType.INSTANCE);
+ } else {
+ if(onAnn.value().length == 0) {
+ whereToRun.add(RuntimeType.DAS);
+ whereToRun.add(RuntimeType.INSTANCE);
+ } else {
+ whereToRun.addAll(Arrays.asList(onAnn.value()));
+ }
+ }
+ }
+
+ @Override
+ public void execute(AdminCommandContext ctxt) {
+ Thread thread = Thread.currentThread();
+ ClassLoader origCL = thread.getContextClassLoader();
+ ClassLoader ccl = sc.getCommonClassLoader();
+ if (progressStatus != null) {
+ ctxt = new AdminCommandContextForInstance(ctxt, progressStatus);
+ }
+ if (origCL != ccl) {
+ try {
+ thread.setContextClassLoader(ccl);
+ if (command instanceof AdminCommandSecurity.Preauthorization) {
+ ((AdminCommandSecurity.Preauthorization) command).preAuthorization(ctxt);
+ }
+ command.execute(ctxt);
+ } finally {
+ thread.setContextClassLoader(origCL);
+ }
+ } else {
+ if (command instanceof AdminCommandSecurity.Preauthorization) {
+ ((AdminCommandSecurity.Preauthorization) command).preAuthorization(ctxt);
+ }
+ command.execute(ctxt);
+ }
+ }
+
+ @Override
+ public AdminCommand getCommand() {
+ return this.command;
+ }
+
+ @Override
+ public boolean toBeExecutedBefore() {
+ return timing.equals(Supplemental.Timing.Before);
+ }
+
+ @Override
+ public boolean toBeExecutedAfter() {
+ return timing.equals(Supplemental.Timing.After);
+ }
+
+ @Override
+ public boolean toBeExecutedAfterReplication() {
+ return timing.equals(Supplemental.Timing.AfterReplication);
+ }
+
+ @Override
+ public FailurePolicy onFailure() {
+ return failurePolicy;
+ }
+
+ @Override
+ public List<RuntimeType> whereToRun() {
+ return whereToRun;
+ }
+
+ @Override
+ public ProgressStatus getProgressStatus() {
+ return progressStatus;
+ }
+
+ @Override
+ public void setProgressStatus(ProgressStatus progressStatus) {
+ this.progressStatus = progressStatus;
+ }
+
+ @Override
+ public Progress getProgressAnnotation() {
+ return progressAnnotation;
+ }
+
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/UptimeCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/UptimeCommand.java
new file mode 100644
index 0000000..a5e09dd
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/UptimeCommand.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import org.glassfish.api.Param;
+import org.glassfish.server.ServerEnvironmentImpl;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandLock;
+import org.glassfish.api.I18n;
+import org.glassfish.api.ActionReport;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PerLookup;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.universal.Duration;
+import org.glassfish.api.admin.*;
+
+import javax.inject.Inject;
+
+/**
+ * uptime command
+ * Reports on how long the server has been running.
+ *
+ */
+@Service(name = "uptime")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("uptime")
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="uptime",
+ description="Uptime",
+ useForAuthorization=true)
+})
+public class UptimeCommand implements AdminCommand {
+
+ @Inject
+ ServerEnvironmentImpl env;
+ @Param(name = "milliseconds", optional = true, defaultValue = "false")
+ Boolean milliseconds;
+
+ public void execute(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+ long totalTime_ms = getUptime();
+ String totalTime_mss = "" + totalTime_ms;
+ Duration duration = new Duration(totalTime_ms);
+ duration.setTerse();
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ String message;
+
+ if (milliseconds)
+ message = totalTime_mss;
+ else
+ message = localStrings.getLocalString("uptime.output.terse", "Uptime: {0}", duration);
+
+ report.setMessage(message);
+ report.getTopMessagePart().addProperty("milliseconds", totalTime_mss);
+ }
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(UptimeCommand.class);
+
+ private long getUptime() {
+ RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
+ long totalTime_ms = -1;
+
+ if (mxbean != null)
+ totalTime_ms = mxbean.getUptime();
+
+ if (totalTime_ms <= 0) {
+ long start = env.getStartupContext().getCreationTime();
+ totalTime_ms = System.currentTimeMillis() - start;
+ }
+ return totalTime_ms;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/V2DottedNameSupport.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/V2DottedNameSupport.java
new file mode 100644
index 0000000..c76cd1a
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/V2DottedNameSupport.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.Dom;
+import org.glassfish.api.admin.config.Named;
+import org.glassfish.api.admin.config.ReferenceContainer;
+
+import java.util.*;
+
+import com.sun.enterprise.config.serverbeans.*;
+
+/**
+ * Utility class for all V2 style related dotted names commands.
+ *
+ * User: Jerome Dochez
+ * Date: Jul 9, 2008
+ * Time: 11:38:50 PM
+ */
+public class V2DottedNameSupport {
+
+ public Map<Dom, String> getAllDottedNodes(ConfigBeanProxy proxy) {
+ return getAllDottedNodes(Dom.unwrap(proxy));
+ }
+
+ public Map<Dom, String> getAllDottedNodes(Dom root) {
+
+ Map<Dom, String> result = new HashMap<Dom, String>();
+ getAllSubDottedNames(null, root, result);
+ return result;
+ }
+
+ protected void getAllSubDottedNames(String prefix, Dom parent, Map<Dom, String> result) {
+
+ Set<String> elementNames = parent.getElementNames();
+
+ for (String childName : elementNames) {
+
+ // by default, it's a collection unless I can find the model for it
+ // and ensure this is one or not.
+ // not finding the model usually means that it was a "*" element therefore
+ // a collection.
+ boolean collection = true;
+ if (parent.model.findIgnoreCase(childName)!=null) {
+ // if this is a leaf node, we should really treat it as an attribute.
+ if (parent.model.getElement(childName).isLeaf())
+ continue;
+ collection = parent.model.getElement(childName).isCollection();
+
+ }
+
+ for (Dom child : parent.nodeElements(childName)) {
+
+ StringBuffer newPrefix = new StringBuffer();
+ if (prefix==null) {
+ newPrefix.append(childName);
+ } else {
+ newPrefix.append(prefix).append(".").append(childName);
+ }
+
+ if (collection) {
+
+ String name = child.getKey();
+ if (name==null) {
+ name = child.attribute("name");
+ }
+
+ if (name!=null) {
+ newPrefix.append(".").append(name);
+ }
+ // now traverse the child
+ getAllSubDottedNames(newPrefix.toString(), child, result);
+ } else {
+ getAllSubDottedNames(newPrefix.toString(), child, result);
+
+ }
+ }
+ }
+ if (prefix!=null) {
+ result.put(parent, prefix);
+ }
+ }
+
+ public Map<String, String> getNodeAttributes(Dom node, String prefix) {
+ Map<String, String> result = new HashMap<String, String>();
+ for (String attrName : node.model.getAttributeNames()) {
+ String value = (String) node.model.findIgnoreCase(attrName).get(node, String.class);
+ if (value!=null) {
+ result.put(attrName, value);
+ }
+ }
+ for (String leafName : node.model.getLeafElementNames()) {
+ List values = node.leafElements(leafName);
+ Iterator i = values.iterator();
+ StringBuffer value = new StringBuffer();
+ while (i.hasNext()) {
+ String nextValue = (String) i.next();
+
+ if (nextValue!=null) {
+ value.append(nextValue);
+ if(i.hasNext()) {
+ value.append(",");
+ }
+ }
+ }
+ result.put(leafName, value.toString());
+ }
+ return result;
+ }
+
+ public Map<Dom, String> getMatchingNodes(Map<Dom, String> nodes, String pattern) {
+
+ Map<Dom, String> result = new HashMap<Dom, String>();
+ for (Map.Entry<Dom, String> entry : nodes.entrySet()) {
+
+ String dottedName = entry.getValue();
+ if (matches(dottedName, pattern)) {
+ result.put(entry.getKey(), entry.getValue());
+ }
+ }
+ return result;
+ }
+
+ public boolean matches(String dottedName, String pattern) {
+ StringTokenizer patternToken = new StringTokenizer(pattern, ".");
+ if (patternToken.hasMoreElements()) {
+ String token = (String) patternToken.nextElement();
+ if (token.startsWith("*")) {
+ // let's find the end delimiter...
+ if (token.length()>1) {
+ String delim = token.substring(1);
+ if (dottedName.indexOf(delim)!=-1) {
+ // found the delimiter...
+ // we have to be careful, the delimiter can be at the end of the string...
+ String remaining = dottedName.substring(dottedName.indexOf(delim) + delim.length());
+ if (remaining.length()==0) {
+ // no more dotted names, better be done with the pattern
+ return !patternToken.hasMoreElements();
+ } else {
+ remaining = remaining.substring(1);
+ }
+ if (patternToken.hasMoreElements()) {
+ return matches(remaining, pattern.substring(token.length()+1));
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ } else {
+ if (patternToken.hasMoreElements()) {
+ // now this can be tricky, seems like the get/set can accept something like *.config
+ // which really means *.*.*.config for the pattern matching mechanism.
+ // so instead of jumping one dotted name token, we may need to jump multiple tokens
+ // until we find the next delimiter, let's find this first.
+ String delim = (String) patternToken.nextElement();
+ if (dottedName.lastIndexOf('.') == -1) {
+ // more pattern, but no more dotted names.
+ // unless the pattern is "*", we don't have a match
+ if (delim.equals("*")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ // we are not going to check if the delim is a attribute, it has to be an element name.
+ // we will leave the attribute checking to someone else.
+ if (dottedName.contains("." + delim)) {
+ String remaining = dottedName.substring(dottedName.indexOf("." + delim) + 1);
+ return matches(remaining,
+ pattern.substring(token.length()+1));
+ } else {
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+ } else {
+ String delim;
+ if (token.lastIndexOf("*")!=-1) {
+ delim = token.substring(0, token.lastIndexOf("*"));
+ } else {
+ delim = token;
+ }
+ if (matchName(dottedName, delim)) {
+ if (patternToken.hasMoreElements()) {
+ if (dottedName.length()<=delim.length()+1) {
+ if ((pattern.substring(token.length()+1)).equals("*")) {
+ return true;
+ } else {
+ // end of our name and more pattern to go...
+ return false;
+ }
+ }
+ String remaining = dottedName.substring(delim.length()+1);
+ return matches(remaining, pattern.substring(token.length()+1));
+ } else {
+ if (dottedName.length()>delim.length()) {
+ String remaining = dottedName.substring(delim.length()+1);
+ // if we have more dotted names (with grandchildren elements)
+ // we don't match
+ if (remaining.indexOf('.')!=-1) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ // no more pattern, no more dotted name, this is matching.
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ } else {
+ // patter is exhausted, only elements one level down should be returned
+ return dottedName.indexOf(".")==-1;
+ }
+ }
+
+ protected boolean matchName(String a, String b) {
+ String nextTokenName = a;
+ if (a.indexOf('.')!=-1) {
+ nextTokenName = a.substring(0, a.indexOf('.'));
+ }
+
+ if (nextTokenName.equals(b)) {
+ return true;
+ }
+ if (nextTokenName.replace('_', '-').equals(b.replace('_', '-'))) {
+ return true;
+ }
+ return false;
+ }
+
+ final static class TreeNode {
+ final Dom node;
+ final String name;
+ final String relativeName;
+ public TreeNode(Dom node, String name, String relativeName) {
+ this.node = node;
+ this.name = name;
+ this.relativeName = relativeName;
+ }
+ }
+
+ public TreeNode[] getAliasedParent(Domain domain, String prefix) {
+
+ // let's get the potential aliased element name
+ String name;
+ String newPrefix;
+ if (prefix.indexOf('.') != -1) {
+ name = prefix.substring(0, prefix.indexOf('.'));
+ newPrefix = prefix.substring(name.length()+1);
+ } else {
+ name = prefix;
+ newPrefix="";
+ }
+
+ // check for resources
+ if (newPrefix.startsWith("resources")) {
+ String relativeName = newPrefix;
+ if (newPrefix.indexOf('.') != -1) {
+ String str = newPrefix.substring(0, newPrefix.indexOf('.'));
+ relativeName = newPrefix.substring(str.length() + 1);
+ name += "." + str;
+ }
+ TreeNode [] result = new TreeNode[1];
+ result[0] = new TreeNode(Dom.unwrap(domain.getResources()), name, relativeName);
+ return result;
+ }
+
+ // server-config
+ for (Config config : domain.getConfigs().getConfig()) {
+ if (config.getName().equals(name)) {
+ return new TreeNode[] {
+ new TreeNode(Dom.unwrap(config), name, newPrefix)
+ };
+ }
+ }
+
+ // this is getting a bit more complicated, as the name can be the server or cluster name
+ // yet, the aliasing should return both the server-config
+
+ // server `
+ Named[] nodes = getNamedNodes(domain.getServers().getServer(),
+ domain.getConfigs().getConfig(), name);
+
+ if (nodes==null && domain.getClusters()!=null) {
+ // no luck with server, try cluster.
+ nodes = getNamedNodes(domain.getClusters().getCluster(),
+ domain.getConfigs().getConfig(), name);
+ }
+ if (nodes!=null) {
+ TreeNode[] result = new TreeNode[nodes.length];
+ for (int i=0;i<nodes.length;i++) {
+ result[i] = new TreeNode(Dom.unwrap((ConfigBeanProxy) nodes[i]), name, newPrefix);
+ }
+ return result;
+ }
+
+ return new TreeNode[] {
+ //new TreeNode(Dom.unwrap(domain), name, newPrefix)
+ new TreeNode(Dom.unwrap(domain), "", prefix)
+ };
+ }
+
+ public Named[] getNamedNodes(List<? extends Named> target, List<? extends Named>references, String name) {
+ for (Named config : target) {
+ if (config.getName().equals(name)) {
+ if (config instanceof ReferenceContainer) {
+ for (Named reference : references) {
+ if (reference.getName().equals(((ReferenceContainer) config).getReference())) {
+ return new Named[] {
+ config, reference
+ };
+ }
+ }
+ } else {
+ return new Named[] { config };
+ }
+ }
+ }
+ return null;
+ }
+
+ public List<Map.Entry> applyOverrideRules(List<Map.Entry> nodes) {
+ HashMap<String, Map.Entry> store = new HashMap<String, Map.Entry>();
+ for (int i=0; i<nodes.size(); i++) {
+ Map.Entry<Dom, String> currentNode = nodes.get(i);
+ Map.Entry<Dom, String> storedNode = store.get(currentNode.getValue());
+ if(storedNode == null) {
+ store.put(currentNode.getValue(), currentNode);
+ continue;
+ }
+ int storedNodePrecedenceLevel = getPrecedenceLevel(storedNode.getKey());
+ int currNodePrecedenceLevel = getPrecedenceLevel(currentNode.getKey());
+ if(storedNodePrecedenceLevel < currNodePrecedenceLevel)
+ store.put(currentNode.getValue(), currentNode);
+ }
+ List<Map.Entry> finalList = new ArrayList<Map.Entry>();
+ finalList.addAll(store.values());
+ store.clear();
+ return finalList;
+ }
+
+ private int getPrecedenceLevel(Dom entry) {
+ String parent = entry.parent().getImplementation();
+ int level = 4;
+ if(Config.class.getCanonicalName().equals(parent))
+ level = 1;
+ if(Cluster.class.getCanonicalName().equals(parent))
+ level = 2;
+ if(Server.class.getCanonicalName().equals(parent))
+ level = 3;
+ return level;
+ }
+
+ public List<Map.Entry> sortNodesByDottedName(Map<Dom, String> nodes) {
+ List<Map.Entry> mapEntries = new ArrayList(nodes.entrySet());
+ Collections.sort(mapEntries, new Comparator() {
+ public int compare(Object o1, Object o2) {
+ return (((String)(((Map.Entry) (o1)).getValue())).compareTo((String)(((Map.Entry) (o2)).getValue())));
+ }
+ });
+ return mapEntries;
+ }
+
+ public List<org.glassfish.flashlight.datatree.TreeNode> sortTreeNodesByCompletePathName(List<org.glassfish.flashlight.datatree.TreeNode> nodes) {
+ Collections.sort(nodes, new Comparator() {
+ public int compare(Object o1, Object o2) {
+ return (((String)(((org.glassfish.flashlight.datatree.TreeNode) (o1)).getCompletePathName())).compareTo(
+ (String)(((org.glassfish.flashlight.datatree.TreeNode) (o2)).getCompletePathName())));
+ }
+ });
+ return nodes;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/VersionCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/VersionCommand.java
new file mode 100644
index 0000000..0da345e
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/VersionCommand.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.appserv.server.util.Version;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import java.util.Properties;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.ActionReport.ExitCode;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Return the version and build number
+ *
+ * @author Jerome Dochez
+ */
+@Service(name="version")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("version.command")
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="version",
+ description="version",
+ useForAuthorization=true)
+})
+public class VersionCommand implements AdminCommand {
+
+ @Param(optional=true, defaultValue="false", shortName = "v")
+ Boolean verbose;
+
+ final private static LocalStringManagerImpl strings = new LocalStringManagerImpl(VersionCommand.class);
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ String vers;
+ if (verbose) {
+ vers = strings.getLocalString("version.verbose",
+ "{0}, JRE version {1}",
+ Version.getFullVersion(), System.getProperty("java.version"));
+ } else {
+ vers = strings.getLocalString("version",
+ "{0}", Version.getFullVersion());
+ }
+ ActionReport report = context.getActionReport();
+ Properties ep = new Properties();
+ ep.setProperty("version", Version.getVersion());
+ ep.setProperty("full-version", Version.getFullVersion());
+ ep.setProperty("version-number", Version.getVersionNumber());
+ report.setExtraProperties(ep);
+ report.setActionExitCode(ExitCode.SUCCESS);
+ report.setMessage(vers);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdapterState.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdapterState.java
new file mode 100644
index 0000000..5f43d5c
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdapterState.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.adapter;
+
+/** A package-private class that holds the state of the admin adapter.
+ * It also acts as a lock that needs to be synchronized externally.
+ * Note that this class is not thread-safe on its own.
+ * @author केदार (km@dev.java.net)
+ * @since GlassFish V3
+ */
+enum AdapterState {
+
+ UNINITIAZED("state.uninitialized", "The Admin Console Adapter is not yet initialized."),
+ AUTHENTICATING("state.authenticating", "Authentication required before the Admin Console can be installed."),
+ PERMISSION_NEEDED("state.permissionNeeded", "The Admin Console requires your permission before it can be downloaded or installed."),
+ PERMISSION_GRANTED("state.permissionGranted", "The Admin Console has your permission to downloaded and install."),
+ CANCELED("state.canceled", "The Admin Console installation has been canceled."),
+ DOWNLOADING("state.downloading", "The Admin Console Web Application is downloading..."),
+ DOWNLOADED("state.downloaded", "The Admin Console Web Application has been downloaded."),
+ EXPANDING("state.expanding", "The Admin Console war file is expanding..."),
+ EXPANDED("state.expanded", "The Admin Console war file has been expanded."),
+ INSTALLING("state.installing", "The Admin Console is installing..."),
+ APPLICATION_INSTALLED_BUT_NOT_LOADED("state.installedNotLoaded", "The Admin Console is already installed, but not yet loaded."),
+ APPLICATION_LOADING("state.loading", "The Admin Console is starting. Please wait."),
+ APPLICATION_LOADED("state.loaded", "The Admin Console application is loaded."),
+ APPLICATION_NOT_INSTALLED("state.notInstalled", "The Admin Console Application is not yet installed."),
+ APPLICATION_PREPARE_UPGRADE("state.prepareRedeploy", "Preparing to upgrade Admin Console Application..."),
+ APPLICATION_BACKUP_FALED("state.backupFailed", "Cannot backup previous version of __admingui"),
+ APPLICATION_CLEANUP_FALED("state.cleanupFailed", "Exception while cleaning previous instance of admin GUI"),
+ APPLICATION_BACKUP_CLEANING("state.cleaningBackup", "Cleaning up temporary backup file..."),
+ APPLICATION_BACKUP_CLEANED("state.cleanupFailed", "Temporary backup file removed"),
+ APPLICATION_RESTORE("state.restore", "Restoring previously deployed Admin Console..."),
+ APPLICATION_UPGRADE_FALED("state.upgradeFailed", "Cannot upgrade Admin Console."),
+ WELCOME_TO("status.welcometo", "Welcome to ");
+
+
+ private final String desc;
+ private final String i18nKey;
+
+ private AdapterState(String i18nKey, String desc) {
+ this.i18nKey = i18nKey;
+ this.desc = desc;
+ }
+
+ /**
+ * This is the key that should be used to retrieve the localized message from a properties file.
+ */
+ public String getI18NKey() {
+ return i18nKey;
+ }
+
+ @Override
+ public String toString() {
+ return (desc);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdminConsoleAdapter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdminConsoleAdapter.java
new file mode 100644
index 0000000..c7ce052
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdminConsoleAdapter.java
@@ -0,0 +1,853 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.adapter;
+
+import com.sun.appserv.server.util.Version;
+import com.sun.enterprise.config.serverbeans.*;
+import com.sun.enterprise.v3.admin.AdminConsoleConfigUpgrade;
+import java.beans.PropertyVetoException;
+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.net.URL;
+import java.net.URLConnection;
+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.inject.Inject;
+import javax.inject.Named;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.container.Adapter;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.api.event.RestrictTo;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+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.PostConstruct;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.data.ApplicationRegistry;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.glassfish.server.ServerEnvironmentImpl;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+import org.jvnet.hk2.config.types.Property;
+
+/**
+ * An HK-2 Service that provides the functionality so that admin console access
+ * is handled properly. The general contract of this adapter is as follows: <ol>
+ * <li>This adapter is *always* installed as a Grizzly adapter for a particular
+ * URL designated as admin URL in domain.xml. This translates to context-root of
+ * admin console application. </li> <li>When the control comes to the adapter for
+ * the first time, user is asked to confirm if downloading the application is OK.
+ * In that case, the admin console application is downloaded and expanded. While
+ * the download and installation is happening, all the clients or browser
+ * refreshes get a status message. No push from the server side is attempted
+ * (yet). After the application is "installed", ApplicationLoaderService is
+ * contacted, so that the application is loaded by the containers. This
+ * application is available as a
+ * <code> system-application </code> and is persisted as such in the domain.xml.
+ * </li> <li>Even after this application is available, we don't load it on server
+ * startup by default. It is always loaded
+ * <code> on demand </code>. Hence, this adapter will always be available to
+ * find out if application is loaded and load it in the container(s) if it is
+ * not. If the application is already loaded, it simply exits. </li> </ol>
+ *
+ * @author केदार (km@dev.java.net)
+ * @author Ken Paulsen (kenpaulsen@dev.java.net)
+ * @author Siraj Ghaffar (sirajg@dev.java.net)
+ * @since GlassFish V3 (March 2008)
+ */
+@Service
+public final class AdminConsoleAdapter extends HttpHandler implements Adapter, PostConstruct, EventListener {
+
+ @Inject
+ ServerEnvironmentImpl env;
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ AdminService adminService;
+ private String contextRoot;
+ private File warFile; // GF Admin Console War File Location
+ private AdapterState stateMsg = AdapterState.UNINITIAZED;
+ private boolean installing = false;
+ private boolean isOK = false; // FIXME: initialize this with previous user choice
+ private AdminConsoleConfigUpgrade adminConsoleConfigUpgrade = null;
+ private final CountDownLatch latch = new CountDownLatch(1);
+ @Inject
+ ApplicationRegistry appRegistry;
+ @Inject
+ Domain domain;
+ @Inject
+ ServiceLocator habitat;
+ @Inject
+ Events events;
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config serverConfig;
+
+ AdminEndpointDecider epd;
+ private static final Logger logger = KernelLoggerInfo.getLogger();
+ private String statusHtml;
+ private String initHtml;
+ private boolean isRegistered = false;
+ private ResourceBundle bundle;
+ //don't change the following without changing the html pages
+ private static final String MYURL_TOKEN = "%%%MYURL%%%";
+ private static final String STATUS_TOKEN = "%%%STATUS%%%";
+ private static final String REDIRECT_TOKEN = "%%%LOCATION%%%";
+ private static final String RESOURCE_PACKAGE = "com/sun/enterprise/v3/admin/adapter";
+ private static final String INSTALL_ROOT = "com.sun.aas.installRoot";
+ static final String ADMIN_APP_NAME = ServerEnvironmentImpl.DEFAULT_ADMIN_CONSOLE_APP_NAME;
+ private boolean isRestStarted = false;
+ private boolean isRestBeingStarted = false;
+
+ /**
+ * Constructor.
+ */
+ public AdminConsoleAdapter() throws IOException {
+ initHtml = Utils.packageResource2String("downloadgui.html");
+ statusHtml = Utils.packageResource2String("status.html");
+ }
+
+ /**
+ *
+ */
+ @Override
+ public String getContextRoot() {
+ return epd.getGuiContextRoot(); //default is /admin
+ }
+
+ @Override
+ public final HttpHandler getHttpService() {
+ return this;
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void service(Request req, Response res) {
+
+ bundle = getResourceBundle(req.getLocale());
+
+ Method method = req.getMethod();
+ if (!checkHttpMethodAllowed(method)) {
+ res.setStatus(java.net.HttpURLConnection.HTTP_BAD_METHOD,
+ method.getMethodString() + " " + bundle.getString("http.bad.method"));
+ res.setHeader("Allow", getAllowedHttpMethodsAsString());
+ return;
+ }
+ if (!env.isDas()) {
+ sendStatusNotDAS(req, res);
+ return;
+ }
+
+ //This is needed to support the case where user update to 3.1 from previous release, and didn't run the upgrade tool.
+ if (adminConsoleConfigUpgrade == null) {
+ adminConsoleConfigUpgrade = habitat.getService(AdminConsoleConfigUpgrade.class);
+ }
+
+ try {
+ if (!latch.await(100L, TimeUnit.SECONDS)) {
+ // todo : better error reporting.
+ logger.log(Level.SEVERE, KernelLoggerInfo.consoleRequestTimeout);
+ return;
+ }
+ } catch (InterruptedException ex) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.consoleCannotProcess);
+ return;
+ }
+ logRequest(req);
+ if (isResourceRequest(req)) {
+ try {
+ handleResourceRequest(req, res);
+ } catch (IOException ioe) {
+ if (logger.isLoggable(Level.SEVERE)) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.consoleResourceError,
+ new Object[]{req.getRequestURI(), ioe.toString()});
+ }
+ if (logger.isLoggable(Level.FINE)) {
+ logger.log(Level.FINE,
+ ioe.toString(),
+ ioe);
+ }
+ }
+ return;
+ }
+ res.setContentType("text/html; charset=UTF-8");
+
+ // simple get request use via javascript to give back the console status (starting with :::)
+ // as a simple string.
+ // see usage in status.html
+
+
+ String serverVersion = Version.getFullVersion();
+
+ if ("/testifbackendisready.html".equals(req.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 = AdapterState.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 = AdapterState.WELCOME_TO.toString() + " " + serverVersion + ".";
+ }
+ status += "\n" + serverVersion;
+ try {
+ OutputBuffer ob = getOutputBuffer(res);
+
+ byte[] bytes = (":::" + status).getBytes("UTF-8");
+ res.setContentLength(bytes.length);
+ ob.write(bytes, 0, bytes.length);
+ ob.flush();
+
+ } catch (IOException ex) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.consoleResourceError, ex);
+ }
+
+
+ return;
+ }
+ if (isApplicationLoaded()) {
+ // Let this pass to the admin console (do nothing)
+ handleLoadedState();
+ } else {
+ // if the admin console is not loaded, and someone use the REST access,
+ //browsers also request the favicon icon... Since we do not want to load
+ // the admin gui just to return a non existing icon,
+ //we just return without loading the entire console...
+ if ("/favicon.ico".equals(req.getRequestURI())) {
+ return;
+ }
+ if (!isRestStarted) {
+ forceRestModuleLoad(req);
+ }
+ synchronized(this) {
+ if (isInstalling()) {
+ sendStatusPage(req, res);
+ } else {
+ if (isApplicationLoaded()) {
+ // Double check here that it is not yet loaded (not
+ // likely, but possible)
+ handleLoadedState();
+ }else {
+ loadConsole();
+ sendStatusPage(req, res);
+ }
+ }
+ }
+
+ }
+
+ }
+
+ 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);
+ }
+ }
+
+ /**
+ * @param req the Request
+ * @return <code>true</code> if the request is for a resource with a known content
+ * type otherwise <code>false</code>.
+ */
+ private boolean isResourceRequest(Request req) {
+ return (getContentType(req.getRequestURI()) != null);
+ }
+
+ /**
+ * All that needs to happen for the REST module to be initialized is a request
+ * of some sort. Here, we don't care about the response, so we make the request
+ * then close the stream and move on.
+ */
+ private void forceRestModuleLoad(final Request req) {
+ if (isRestBeingStarted==true){
+ return;
+ }
+ isRestBeingStarted = true;
+ Thread thread = new Thread("Force REST Module Load Thread") {
+ @Override
+ public void run() {
+ initRest();
+ }
+ };
+ thread.setDaemon(true);
+ thread.start();
+ }
+
+ private String getContentType(String resource) {
+
+ if (resource == null || resource.length() == 0) {
+ return null;
+ }
+ // this may need to be expanded upon the future, in which case, the
+ // current implementation may not be worth maintaining
+ 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 req, Response res)
+ throws IOException {
+
+ String resourcePath = RESOURCE_PACKAGE + req.getRequestURI();
+
+ ClassLoader loader = AdminConsoleAdapter.class.getClassLoader();
+
+ InputStream in = null;
+ try {
+ in = loader.getResourceAsStream(resourcePath);
+ if (in == null) {
+ logger.log(Level.WARNING, KernelLoggerInfo.consoleResourceNotFound, resourcePath);
+ return;
+ }
+ byte[] buf = new byte[512];
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
+ for (int i = in.read(buf); i != -1; i = in.read(buf)) {
+ baos.write(buf, 0, i);
+ }
+ String contentType = getContentType(resourcePath);
+ if (contentType != null) {
+ res.setContentType(contentType);
+ }
+ res.setContentLength(baos.size());
+ OutputStream out = res.getOutputStream();
+ baos.writeTo(out);
+ out.flush();
+
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+
+ }
+
+ boolean isApplicationLoaded() {
+ return (stateMsg == AdapterState.APPLICATION_LOADED);
+ }
+
+ /**
+ *
+ */
+ boolean isInstalling() {
+ return installing;
+ }
+
+ /**
+ *
+ */
+ void setInstalling(boolean flag) {
+ installing = flag;
+ }
+
+ /**
+ * Checks whether this adapter has been registered as a network endpoint.
+ */
+ @Override
+ public boolean isRegistered() {
+ return isRegistered;
+ }
+
+ /**
+ * Marks this adapter as having been registered or unregistered as a
+ * network endpoint
+ */
+ @Override
+ public void setRegistered(boolean isRegistered) {
+ this.isRegistered = isRegistered;
+ }
+
+ /**
+ * <p> This method sets the current state.</p>
+ */
+ void setStateMsg(AdapterState msg) {
+ stateMsg = msg;
+ logger.log(Level.FINE, msg.toString());
+ }
+
+ /**
+ * <p> This method returns the current state, which will be one of the
+ * valid values defined by {@link AdapterState}.</p>
+ */
+ AdapterState getStateMsg() {
+ return stateMsg;
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void postConstruct() {
+ events.register(this);
+ //set up the environment properly
+ init();
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void event(@RestrictTo(EventTypes.SERVER_READY_NAME) Event event) {
+ latch.countDown();
+ if (logger != null) {
+ logger.log(Level.FINE, "AdminConsoleAdapter is ready.");
+ }
+ }
+
+ /**
+ *
+ */
+ private void init() {
+ Property locProp = adminService.getProperty(ServerTags.ADMIN_CONSOLE_DOWNLOAD_LOCATION);
+ if (locProp == null || locProp.getValue() == null || locProp.getValue().equals("")) {
+ String iRoot = System.getProperty(INSTALL_ROOT) + "/lib/install/applications/admingui.war";
+ warFile = new File(iRoot.replace('/', File.separatorChar));
+ writeAdminServiceProp(ServerTags.ADMIN_CONSOLE_DOWNLOAD_LOCATION, "${" + INSTALL_ROOT + "}/lib/install/applications/admingui.war");
+ } else {
+ //For any non-absolute path, we start from the installation, ie glassfish5
+ //eg, v3 prelude upgrade, where the location property was "glassfish/lib..."
+ String locValue = locProp.getValue();
+ warFile = new File(locValue);
+ if (!warFile.isAbsolute()) {
+ File tmp = new File(System.getProperty(INSTALL_ROOT), "..");
+ warFile = new File(tmp, locValue);
+ }
+ }
+
+ if (logger.isLoggable(Level.FINE)) {
+ logger.log(Level.FINE, "Admin Console download location: {0}", warFile.getAbsolutePath());
+ }
+
+ initState();
+
+ try {
+ epd = new AdminEndpointDecider(serverConfig);
+ contextRoot = epd.getGuiContextRoot();
+ } catch (Exception ex) {
+ logger.log(Level.INFO, KernelLoggerInfo.consoleCannotInitialize, ex);
+ return;
+ }
+ }
+
+ void initRest() {
+ InputStream is = null;
+ try {
+ NetworkListener nl = domain.getServerNamed("server").getConfig().getNetworkConfig()
+ .getNetworkListener("admin-listener");
+ SecureAdmin secureAdmin = habitat.getService(SecureAdmin.class);
+
+ URL url = new URL(
+ (SecureAdmin.Util.isEnabled(secureAdmin) ? "https" : "http"),
+ nl.getAddress(),
+ Integer.parseInt(nl.getPort()),
+ "/management/domain");
+ URLConnection conn = url.openConnection();
+ is = conn.getInputStream();
+ isRestStarted = true;
+ } catch (Exception ex) {
+ logger.log(Level.FINE, null, ex);
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException ex1) {
+ logger.log(Level.FINE, null, ex1);
+ }
+ }
+ }
+ }
+
+
+ /**
+ *
+ */
+ private void initState() {
+ // It is a given that the application is NOT loaded to begin with
+ if (appExistsInConfig()) {
+ isOK = true; // FIXME: I don't think this is good enough
+ setStateMsg(AdapterState.APPLICATION_INSTALLED_BUT_NOT_LOADED);
+ } else if (new File(warFile.getParentFile(), ADMIN_APP_NAME).exists() || warFile.exists()) {
+ // The exploded dir, or the .war exists... mark as downloded
+ if (logger.isLoggable(Level.FINE)) {
+ setStateMsg(AdapterState.DOWNLOADED);
+ }
+ isOK = true;
+ } else {
+ setStateMsg(AdapterState.APPLICATION_NOT_INSTALLED);
+ }
+ }
+
+ /**
+ *
+ */
+ private boolean appExistsInConfig() {
+ return (getConfig() != null);
+ }
+
+ /**
+ *
+ */
+ Application getConfig() {
+ //no application-ref logic here -- that's on purpose for now
+ Application app = domain.getSystemApplicationReferencedFrom(env.getInstanceName(), ADMIN_APP_NAME);
+
+ return app;
+ }
+
+ /**
+ *
+ */
+ private void logRequest(Request req) {
+ if (logger.isLoggable(Level.FINE)) {
+ logger.log(Level.FINE, "AdminConsoleAdapter''s STATE IS: {0}", getStateMsg());
+ logger.log(Level.FINE, "Current Thread: {0}", Thread.currentThread().getName());
+ for (final String name : req.getParameterNames()) {
+ final String values = Arrays.toString(req.getParameterValues(name));
+ logger.log(Level.FINE, "Parameter name: {0} values: {1}", new Object[]{name, values});
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ enum InteractionResult {
+
+ OK,
+ CANCEL,
+ FIRST_TIMER;
+ }
+
+ /**
+ * <p> Determines if the user has permission.</p>
+ */
+ private boolean hasPermission(InteractionResult ir) {
+ //do this quickly as this is going to block the grizzly worker thread!
+ //check for returning user?
+ if (ir == InteractionResult.OK) {
+ isOK = true;
+ }
+ return isOK;
+ }
+
+ /**
+ *
+ */
+ private void startThread() {
+ new InstallerThread(this, habitat, domain, env, contextRoot, epd.getGuiHosts()).start();
+ }
+
+ /**
+ *
+ */
+ /*
+ private synchronized InteractionResult getUserInteractionResult(GrizzlyRequest req) {
+ if (req.getParameter(OK_PARAM) != null) {
+ proxyHost = req.getParameter(PROXY_HOST_PARAM);
+ if ((proxyHost != null) && !proxyHost.equals("")) {
+ String ps = req.getParameter(PROXY_PORT_PARAM);
+ try {
+ proxyPort = Integer.parseInt(ps);
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException(
+ "The specified proxy port (" + ps
+ + ") must be a valid port integer!", nfe);
+ }
+ }
+// FIXME: I need to "remember" this answer in a persistent way!! Or it will popup this message EVERY time after the server restarts.
+ setStateMsg(AdapterState.PERMISSION_GRANTED);
+ isOK = true;
+ return InteractionResult.OK;
+ } else if (req.getParameter(CANCEL_PARAM) != null) {
+ // Canceled
+// FIXME: I need to "remember" this answer in a persistent way!! Or it will popup this message EVERY time after the server restarts.
+ setStateMsg(AdapterState.CANCELED);
+ isOK = false;
+ return InteractionResult.CANCEL;
+ }
+
+ // This is a first-timer
+ return InteractionResult.FIRST_TIMER;
+ }
+ *
+ */
+ private OutputBuffer getOutputBuffer(Response res) {
+ res.setStatus(202);
+ res.setContentType("text/html");
+ res.setCharacterEncoding("UTF-8");
+ return res.getOutputBuffer();
+ }
+
+ /**
+ *
+ */
+ private void sendStatusPage(Request req, Response res) {
+ byte[] bytes;
+ try {
+ OutputBuffer ob = getOutputBuffer(res);
+ // 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 = req.getScheme()
+ + "://" + req.getServerName()
+ + ':' + req.getServerPort() + "/login.jsf";
+ localHtml = localHtml.replace(REDIRECT_TOKEN, locationUrl);
+ bytes = localHtml.replace(STATUS_TOKEN, status).getBytes("UTF-8");
+ res.setContentLength(bytes.length);
+ ob.write(bytes, 0, bytes.length);
+ ob.flush();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ *
+ */
+ private void sendStatusNotDAS(Request req, Response res) {
+ byte[] bytes;
+ try {
+ String html = Utils.packageResource2String("statusNotDAS.html");
+ OutputBuffer ob = getOutputBuffer(res);
+ // Replace locale specific Strings
+ String localHtml = replaceTokens(html, bundle);
+
+ bytes = localHtml.getBytes("UTF-8");
+ res.setContentLength(bytes.length);
+ ob.write(bytes, 0, bytes.length);
+ ob.flush();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ * <p> This method returns the resource bundle for localized Strings used
+ * by the AdminConsoleAdapter.</p>
+ *
+ * @param locale The Locale to be used.
+ */
+ private ResourceBundle getResourceBundle(Locale locale) {
+ return ResourceBundle.getBundle(
+ "com.sun.enterprise.v3.admin.adapter.LocalStrings", locale);
+ }
+
+ /**
+ * <p> This method replaces all tokens in text with values from the given
+ * <code>ResourceBundle</code>. A token starts and ends with 3
+ * percent (%) characters. The value between the percent characters
+ * will be used as the key to the given <code>ResourceBundle</code>.
+ * If a key does not exist in the bundle, no substitution will take
+ * place for that token.</p>
+ *
+ * @return The same text except with substituted tokens when available.
+ * @param text The text containing tokens to be replaced.
+ * @param bundle The <code>ResourceBundle</code> with keys for the value
+ */
+ private String replaceTokens(String text, ResourceBundle bundle) {
+ int start = 0, end = 0;
+ String newString = null;
+ StringBuilder buf = new StringBuilder("");
+
+ while (start != -1) {
+ // Find start of token
+ start = text.indexOf("%%%", end);
+ if (start != -1) {
+ // First copy the stuff before the start
+ buf.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
+ buf.append(
+ bundle.getString(text.substring(start, end)));
+ } catch (MissingResourceException ex) {
+ // Unable to find the resource, so we don't do anything
+ buf.append("%%%").append(text.substring(start, end)).append("%%%");
+ }
+
+ // Move past the %%%
+ end += 3;
+ } else {
+ // Add back the %%% because we didn't find a matching end
+ buf.append("%%%");
+
+ // Reset end so we can copy the remainder of the text
+ end = start;
+ }
+ }
+ }
+
+ // Copy the remainder of the text
+ buf.append(text.substring(end));
+
+ // Return the new String
+ return buf.toString();
+ }
+
+ public AdminService getAdminService() {
+ return adminService;
+ }
+
+ private void writeAdminServiceProp(final String propName, final String propValue) {
+ try {
+ ConfigSupport.apply(new SingleConfigCode<AdminService>() {
+
+ @Override
+ public Object run(AdminService adminService) throws PropertyVetoException, TransactionFailure {
+ Property newProp = adminService.createChild(Property.class);
+ adminService.getProperty().add(newProp);
+ newProp.setName(propName);
+ newProp.setValue(propValue);
+ return newProp;
+ }
+ }, adminService);
+ } catch (Exception ex) {
+ logger.log(Level.WARNING, KernelLoggerInfo.consoleCannotWriteProperty,
+ new Object[] {propName, propValue, ex});
+ }
+ }
+
+ /**
+ *
+ */
+ private void handleLoadedState() {
+//System.out.println(" Handle Loaded State!!");
+ // do nothing
+ statusHtml = null;
+ initHtml = null;
+ }
+
+ @Override
+ public int getListenPort() {
+ return epd.getListenPort();
+ }
+
+ @Override
+ public InetAddress getListenAddress() {
+ return epd.getListenAddress();
+ }
+
+ @Override
+ public List<String> getVirtualServers() {
+ return epd.getGuiHosts();
+ }
+// enum HttpMethod {
+// OPTIONS ("OPTIONS"),
+// GET ("GET"),
+// HEAD ("HEAD"),
+// POST ("POST"),
+// PUT ("PUT"),
+// DELETE ("DELETE"),
+// TRACE ("TRACE"),
+// CONNECT ("CONNECT");
+//
+// private String method;
+//
+// HttpMethod(String method) {
+// this.method = method;
+// }
+//
+// static HttpMethod getHttpMethod(String httpMethod) {
+// for (HttpMethod hh: HttpMethod.values()) {
+// if (hh.method.equalsIgnoreCase(httpMethod)) {
+// return hh;
+// }
+// }
+// return null;
+// }
+//
+// String method() {
+// return method;
+// }
+// }
+ private Method[] allowedHttpMethods = {Method.GET, Method.POST, Method.HEAD,
+ Method.DELETE, Method.PUT};
+
+ 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();
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdminConsoleStartupService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdminConsoleStartupService.java
new file mode 100644
index 0000000..cbf6765
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdminConsoleStartupService.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.adapter;
+
+
+
+import com.sun.enterprise.config.serverbeans.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.internal.api.PostStartupRunLevel;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.glassfish.server.ServerEnvironmentImpl;
+import org.jvnet.hk2.annotations.Optional;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.types.Property;
+
+
+@Service(name = "AdminConsoleStartupService")
+@RunLevel(PostStartupRunLevel.VAL)
+public class AdminConsoleStartupService implements PostConstruct {
+
+ @Inject
+ private AdminService adminService;
+
+ @Inject @Optional
+ private AdminConsoleAdapter adminConsoleAdapter = null;
+
+ @Inject
+ private ServerEnvironmentImpl env;
+
+ @Inject
+ private Domain domain;
+
+ private static final Logger logger = KernelLoggerInfo.getLogger();
+ private final long ONE_DAY = 24 * 60 * 60 * 1000;
+
+ @Override
+ public void postConstruct() {
+
+ if (adminConsoleAdapter == null) { // there may be no console in this environment.
+ return;
+ }
+
+ /* This service must run only on the server where the console should run. Currently, that server is DAS. If and when
+ * the console becomes dis-associated with DAS, this logic will need to be modified.
+ */
+ if (!env.isDas())
+ return;
+
+ // FIXME : Use ServerTags, when this is finalized.
+ Property initProp = adminService.getProperty("adminConsoleStartup");
+ String initPropVal = "DEFAULT";
+ if (initProp != null) {
+ initPropVal = initProp.getValue();
+ if ( !(initPropVal.equals("ALWAYS") || initPropVal.equals("NEVER") || initPropVal.equals("DEFAULT"))){
+ initPropVal="DEFAULT";
+ }
+ }
+
+ if (logger.isLoggable(Level.FINE)) {
+ logger.log(Level.FINE, "AdminConsoleStartupService, console loading option is {0}", initPropVal);
+ }
+
+ if (initPropVal.equalsIgnoreCase("DEFAULT")) {
+ handleDefault();
+ } else if (initPropVal.equalsIgnoreCase("ALWAYS")) {
+ handleHigh();
+ }
+ }
+
+ private void handleDefault() {
+ /* if there are servers other than DAS */
+ if ((domain.getServers().getServer().size() > 1)) {
+ if (logger.isLoggable(Level.FINER)) {
+ logger.log(Level.FINER, "AdminConsoleStartup DAS usecase");
+ }
+ handleHigh();
+ return;
+ }
+ // if last access was within a day
+ long currentTime = System.currentTimeMillis();
+ try {
+ long lastTime = getTimeStamp();
+ if (currentTime - lastTime < ONE_DAY) {
+ if (logger.isLoggable(Level.FINER)) {
+ logger.log(Level.FINER, "AdminConsoleStartup frequent user, lastTime = ", lastTime);
+ }
+ handleHigh();
+ }
+ } catch (IOException ex) {
+ logger.fine(ex.getMessage());
+ }
+ }
+
+ private void handleLow() {
+ adminConsoleAdapter.initRest();
+ }
+
+
+ private void handleHigh() {
+ handleLow();
+ synchronized(this) {
+ if (!adminConsoleAdapter.isInstalling() && !adminConsoleAdapter.isApplicationLoaded()) {
+ adminConsoleAdapter.loadConsole();
+ }
+ }
+ }
+
+ private long getTimeStamp() throws IOException {
+ File f = new File(env.getConfigDirPath(), ".consolestate");
+ if (!f.exists())
+ return 0L;
+ return f.lastModified();
+ }
+
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdminEndpointDecider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdminEndpointDecider.java
new file mode 100644
index 0000000..2b2a0f7
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/AdminEndpointDecider.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.adapter;
+
+import com.sun.enterprise.config.serverbeans.AdminService;
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.ServerTags;
+import com.sun.enterprise.v3.admin.AdminAdapter;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.grizzly.config.dom.ThreadPool;
+import org.jvnet.hk2.config.types.Property;
+import org.glassfish.server.ServerEnvironmentImpl;
+
+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 org.glassfish.kernel.KernelLoggerInfo;
+
+/** Makes various decisions about the admin adapters.
+ *
+ * @author केदार (km@dev.java.net)
+ * @since GlassFish V3 (March 2008)
+ */
+public final class AdminEndpointDecider {
+
+ private String asadminContextRoot;
+ private String guiContextRoot;
+ private List<String> asadminHosts; //list of virtual servers for asadmin
+ private List<String> guiHosts; //list of virtual servers for admin GUI
+
+ private int port; // both asadmin and admin GUI are on same port
+ private InetAddress address;
+ private int maxThreadPoolSize = 5;
+ private Config cfg;
+ private Logger log = KernelLoggerInfo.getLogger();
+
+ public static final int ADMIN_PORT = 4848;
+
+ public AdminEndpointDecider(Config cfg) {
+ if (cfg == null || log == null)
+ throw new IllegalArgumentException("config or logger can't be null");
+ this.cfg = cfg;
+ setValues();
+ }
+
+ public int getListenPort() {
+ return port;
+ }
+
+ public InetAddress getListenAddress() {
+ return address;
+ }
+
+ public int getMaxThreadPoolSize() {
+ return maxThreadPoolSize;
+ }
+
+ public List<String> getAsadminHosts() {
+ return asadminHosts;
+ }
+
+ public List<String> getGuiHosts() {
+ return guiHosts;
+ }
+
+ public String getAsadminContextRoot() {
+ return asadminContextRoot;
+ }
+
+ public String getGuiContextRoot() {
+ return guiContextRoot;
+ }
+
+ private void setValues() {
+ asadminContextRoot = AdminAdapter.PREFIX_URI; //can't change
+ //asadminHosts = Collections.emptyList(); //asadmin is handled completely by the adapter, no VS needed
+ NetworkListener nl = cfg.getAdminListener();
+ ThreadPool tp = nl.findThreadPool();
+ if (tp != null) {
+ try {
+ maxThreadPoolSize = Integer.parseInt(tp.getMaxThreadPoolSize());
+ } catch (NumberFormatException ne) {
+ }
+ }
+ String dvs = nl.findHttpProtocol().getHttp().getDefaultVirtualServer();
+ guiHosts = Collections.unmodifiableList(Arrays.asList(dvs));
+ asadminHosts = guiHosts; //same for now
+ try {
+ address = InetAddress.getByName(nl.getAddress());
+ } catch (UnknownHostException e) {
+ throw new IllegalStateException(e);
+ }
+ if (ServerTags.ADMIN_LISTENER_ID.equals(nl.getName())) {
+ guiContextRoot = ""; //at the root context for separate admin-listener
+ try {
+ port = Integer.parseInt(nl.getPort());
+ } catch(NumberFormatException ne) {
+ port = ADMIN_PORT;
+ }
+ }
+ else {
+ try {
+ port = Integer.parseInt(nl.getPort());
+ } catch(NumberFormatException ne) {
+ port = 8080; // this is the last resort
+ }
+ //get the context root from admin-service
+ AdminService as = cfg.getAdminService();
+ if (as == null)
+ guiContextRoot = ServerEnvironmentImpl.DEFAULT_ADMIN_CONSOLE_CONTEXT_ROOT;
+ else
+ setGuiContextRootFromAdminService(as);
+ }
+ }
+
+ private void setGuiContextRootFromAdminService(AdminService as) {
+ for (Property p : as.getProperty()) {
+ setGuiContextRoot(p);
+ }
+ }
+ private void setGuiContextRoot(Property prop) {
+ if (prop == null) {
+ guiContextRoot = ServerEnvironmentImpl.DEFAULT_ADMIN_CONSOLE_CONTEXT_ROOT;
+ return;
+ }
+ if (ServerTags.ADMIN_CONSOLE_CONTEXT_ROOT.equals(prop.getName())) {
+ if (prop.getValue() != null && prop.getValue().startsWith("/")) {
+ guiContextRoot = prop.getValue();
+ log.log(Level.INFO, KernelLoggerInfo.contextRoot, guiContextRoot);
+ } else {
+ log.log(Level.INFO, KernelLoggerInfo.invalidContextRoot, ServerEnvironmentImpl.DEFAULT_ADMIN_CONSOLE_CONTEXT_ROOT);
+ guiContextRoot = ServerEnvironmentImpl.DEFAULT_ADMIN_CONSOLE_CONTEXT_ROOT;
+ }
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/InstallerThread.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/InstallerThread.java
new file mode 100644
index 0000000..5b57f05
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/InstallerThread.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.adapter;
+
+import com.sun.enterprise.config.serverbeans.*;
+import com.sun.enterprise.v3.server.ApplicationLoaderService;
+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.internal.data.ApplicationInfo;
+import org.glassfish.internal.data.ApplicationRegistry;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.kernel.KernelLoggerInfo;
+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;
+
+
+/**
+ * @author kedar
+ * @author Ken Paulsen (ken.paulsen@sun.com)
+ */
+final class InstallerThread extends Thread {
+
+ private final Domain domain;
+ private final ServerEnvironmentImpl env;
+ private final String contextRoot;
+ private final AdminConsoleAdapter adapter;
+ private final ServiceLocator habitat;
+ private final Logger log = KernelLoggerInfo.getLogger();
+ private final List<String> vss;
+
+
+ /**
+ * Constructor.
+ */
+ InstallerThread(AdminConsoleAdapter adapter, ServiceLocator habitat, Domain domain, ServerEnvironmentImpl env, String contextRoot, List<String> vss) {
+
+ this.adapter = adapter;
+ this.habitat = habitat;
+ this.domain = domain;
+ this.env = env;
+ this.contextRoot = contextRoot;
+ this.vss = vss; //defensive copying is not required here
+ }
+
+ /**
+ *
+ */
+ @Override
+ public void run() {
+ try {
+ // The following are the basic steps which are required to get the
+ // Admin Console web application running. Each step ensures that
+ // it has not already been completed and adjusts the state message
+ // accordingly.
+ install();
+ load();
+
+ // From within this Thread mark the installation process complete
+ adapter.setInstalling(false);
+ } catch (Exception ex) {
+ adapter.setInstalling(false);
+ adapter.setStateMsg(AdapterState.APPLICATION_NOT_INSTALLED);
+ log.log(Level.INFO, KernelLoggerInfo.adminGuiInstallProblem, ex);
+ }
+ }
+
+
+ /**
+ * <p> Install the admingui.war file.</p>
+ */
+ private void install() throws Exception {
+ if (domain.getSystemApplicationReferencedFrom(env.getInstanceName(), AdminConsoleAdapter.ADMIN_APP_NAME) != null) {
+ // Application is already installed
+ adapter.setStateMsg(AdapterState.APPLICATION_INSTALLED_BUT_NOT_LOADED);
+ return;
+ }
+
+ // Set the adapter state
+ adapter.setStateMsg(AdapterState.INSTALLING);
+ if (log.isLoggable(Level.FINE)) {
+ log.log(Level.FINE, "Installing the Admin Console Application...");
+ }
+
+ //create the application entry in domain.xml
+ ConfigCode code = new ConfigCode() {
+ @Override
+ public Object run(ConfigBeanProxy... proxies) throws PropertyVetoException, TransactionFailure {
+ SystemApplications sa = (SystemApplications) proxies[0];
+ Application app = sa.createChild(Application.class);
+ sa.getModules().add(app);
+ app.setName(AdminConsoleAdapter.ADMIN_APP_NAME);
+ app.setEnabled(Boolean.TRUE.toString());
+ app.setObjectType("system-admin"); //TODO
+ app.setDirectoryDeployed("true");
+ app.setContextRoot(contextRoot);
+ try {
+ app.setLocation("${com.sun.aas.installRootURI}/lib/install/applications/" + AdminConsoleAdapter.ADMIN_APP_NAME);
+ } catch (Exception me) {
+ // can't do anything
+ throw new RuntimeException(me);
+ }
+ Module singleModule = app.createChild(Module.class);
+ app.getModule().add(singleModule);
+ singleModule.setName(app.getName());
+ Engine webe = singleModule.createChild(Engine.class);
+ webe.setSniffer("web");
+ Engine sece = singleModule.createChild(Engine.class);
+ sece.setSniffer("security");
+ singleModule.getEngines().add(webe);
+ singleModule.getEngines().add(sece);
+ Server s = (Server) proxies[1];
+ List<ApplicationRef> arefs = s.getApplicationRef();
+ ApplicationRef aref = s.createChild(ApplicationRef.class);
+ aref.setRef(app.getName());
+ aref.setEnabled(Boolean.TRUE.toString());
+ aref.setVirtualServers(getVirtualServerList()); //TODO
+ arefs.add(aref);
+ return true;
+ }
+ };
+ Server server = domain.getServerNamed(env.getInstanceName());
+ ConfigSupport.apply(code, domain.getSystemApplications(), server);
+
+ // Set the adapter state
+ adapter.setStateMsg(AdapterState.APPLICATION_INSTALLED_BUT_NOT_LOADED);
+ if (log.isLoggable(Level.FINE)) {
+ log.log(Level.FINE, "Admin Console Application Installed.");
+ }
+ }
+
+ /**
+ *
+ */
+ 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);
+ }
+
+ /**
+ * <p> Load the Admin Console web application.</p>
+ */
+ private void load() {
+ ApplicationRegistry appRegistry = habitat.<ApplicationRegistry>getService(ApplicationRegistry.class);
+ ApplicationInfo appInfo = appRegistry.get(AdminConsoleAdapter.ADMIN_APP_NAME);
+ if (appInfo != null && appInfo.isLoaded()) {
+ // Application is already loaded
+ adapter.setStateMsg(AdapterState.APPLICATION_LOADED);
+ return;
+ }
+
+ // hook for Jerome
+ Application config = adapter.getConfig();
+ if (config == null) {
+ throw new IllegalStateException("Admin Console application has no system app entry!");
+ }
+ // Set adapter state
+ adapter.setStateMsg(AdapterState.APPLICATION_LOADING);
+
+ // Load the Admin Console Application
+ String sn = env.getInstanceName();
+// FIXME: An exception may not be thrown... check for errors!
+ ApplicationRef ref = domain.getApplicationRefInServer(sn, AdminConsoleAdapter.ADMIN_APP_NAME);
+ habitat.<ApplicationLoaderService>getService(ApplicationLoaderService.class).processApplication(config, ref);
+
+ // Set adapter state
+ adapter.setStateMsg(AdapterState.APPLICATION_LOADED);
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/LocalStrings.properties b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/LocalStrings.properties
new file mode 100644
index 0000000..99b4d63
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/LocalStrings.properties
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+
+
+button.ok=OK
+button.cancel=Cancel
+connection.direct=Direct
+connection.proxy=Through a Proxy
+connection.proxy.host=Proxy Host:
+connection.proxy.port=Proxy Port:
+connection.title=Internet Connection
+connection.helpText=If your GlassFish Application Server requires a proxy to reach the Internet, you will need to supply your proxy host and port information.
+console.moreInfo.link=https://glassfish.dev.java.net/
+console.moreInfo.linkText=More about the console
+install.pageTitle=GlassFish Administration Console - Installation
+install.text=The GlassFish Administration Console is not installed. To install the console, specify an Internet connection and click OK.
+product.title=GlassFish Server Administration Console
+status.current=Status:
+status.loading=The console is starting. Please wait.
+status.spin.alt=Status indicator image.
+status.pageTitle=GlassFish Server Administration Console
+status.text=If the browser does not refresh the page automatically please reload the page.
+status.welcometo=Welcome to
+thankYou=Welcome to GlassFish !!
+
+state.uninitialized=The Admin Console Adapter is not yet initialized.
+state.authenticating=Authentication required before the Admin Console can be installed.
+state.permissionNeeded=The Admin Console requires your permission before it can be downloaded or installed.
+state.permissionGranted=The Admin Console has your permission to downloaded and install.
+state.canceled=The Admin Console installation has been canceled.
+state.downloading=The Admin Console Web Application is downloading...
+state.downloaded=The Admin Console Web Application has been downloaded.
+state.expanding=The Admin Console war file is expanding...
+state.expanded=The Admin Console war file has been expanded.
+state.installing=The Admin Console is installing...
+state.installedNotLoaded=The Admin Console is already installed, but not yet loaded.
+state.loading=The Admin Console is starting. Please wait.
+state.loaded=The Admin Console application is loaded.
+state.notInstalled=The Admin Console Application is not yet installed.
+state.prepareRedeploy=Preparing to upgrade Admin Console Application...
+state.cleanupFailed=Exception while cleaning previous instance of admin console
+state.backupFailed=Cannot rename __admingui to __admingui.backup
+state.cleaningBackup=Cleaning up temporary backup file...
+state.cleanupFailed=Temporary backup file removed
+state.restore=Restoring previously deployed Admin Console...
+state.upgradeFailed=Upgrade of Admin Console failed. Check file or directory permission.
+
+
+statusNotAvailable.pageTitle=Administration Console Not Available
+statusNotAvailable.text=The Administration Console is available only from the Domain Administration Server. It is not accessible from a Server Instance.
+
+http.bad.method=method is not allowed
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/Utils.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/Utils.java
new file mode 100644
index 0000000..57fc756
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/Utils.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.adapter;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/** Package-private class to provide utilities.
+ *
+ * @author केदार (km@dev.java.net)
+ * @since GlassFish V3
+ */
+final class Utils {
+
+ /** Reads the given file in this package and returns it as a String.
+ * If there is any problem in reading an IOException is thrown.
+ * @param name representing just the complete name of file to be read, e.g. foo.html
+ * @return String
+ * @throws IOException
+ */
+ static String packageResource2String(String name) throws IOException {
+ String file = Utils.class.getPackage().getName().replace('.', '/') + "/" + name;
+ InputStream is=null;
+ try {
+ is = new BufferedInputStream(Utils.class.getClassLoader().getResourceAsStream(file));
+ byte[] bytes = new byte[1024];
+ int read;
+ StringBuilder sb = new StringBuilder();
+ while ((read = is.read(bytes)) != -1) {
+ sb.append(new String(bytes, 0, read, "UTF-8"));
+ }
+ return ( sb.toString());
+ } finally {
+ if (is!=null) {
+ try {
+ is.close();
+ } catch(IOException ioe) {
+ // ignore
+ }
+ }
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/asynch-1F.gif b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/asynch-1F.gif
new file mode 100644
index 0000000..4fb7c23
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/asynch-1F.gif
Binary files differ
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/backimage.jpg b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/backimage.jpg
new file mode 100644
index 0000000..a2e7d8f
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/backimage.jpg
Binary files differ
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/downloadgui.html b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/downloadgui.html
new file mode 100644
index 0000000..623fa18
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/downloadgui.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<!--
+
+ Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v. 2.0, which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ This Source Code may also be made available under the following Secondary
+ Licenses when the conditions for such availability set forth in the
+ Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ version 2 with the GNU Classpath Exception, which is available at
+ https://www.gnu.org/software/classpath/license.html.
+
+ SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>%%%install.pageTitle%%%</title>
+
+<style type="text/css">
+a:link {color:#003399;text-decoration:none;font-weight:bold;}
+a:visited {color:#003399;text-decoration:none}
+a:hover {color:#003399;text-decoration:underline}
+body {font-family:Arial,Helvetica,sans-serif;font-size:76%;margin:0px;padding:0px;background:#4a5c6a;}
+h1 {padding-top:50px;margin-top:0px;color:#46626e;font-size:21px;}
+h2 {color:#46626e;font-size:16px;}
+h4 {font-style:normal;font-size:.9em;color:#666;}
+* html body {overflow:hidden;}
+* html #footer-wrapper {float:left;position:relative;width:100%;padding-bottom:10010px;margin-bottom:-10000px;background:#4a5c6a;}
+.subtitle {color:#000000;font-size:16px;font-weight:bold;}
+.container {overflow:hidden;text-align:center;background:#d4dbe1;height:435px;}
+.container .column {text-align:left;height:435px;margin:auto;width:540px;padding-left:300px;padding-right:40px;background-image:url(http://download.java.net/glassfish/v3/admingui/download-backimage.jpg);background-repeat:no-repeat;background-color:#FFFFFF;}
+.container #fields {margin-left:22px;margin-top:1em;}
+.container #buttons {padding-left:90px;}
+.container #helptext {margin-left:90px;}
+#footer {clear:both;}
+#header, #footer {font-size:small;text-align:center;padding:0.3em 0;background:#4a5c6a;height:20px;color:#FFFFFF;font-weight:bold;}
+</style>
+
+<script language="javascript">
+function checkHiddenElements(directvalue) {
+ if (!directvalue.checked) {
+ document.getElementById('proxy').style.display = 'block';
+ } else {
+ document.getElementById('proxy').style.display = 'none';
+ }
+}
+</script>
+</head>
+
+<body onload="javascript:checkHiddenElements(document.getElementById('direct'));">
+ <div id="header"></div>
+ <div class="container">
+ <div id="center" class="column">
+ <!-- <div id="page_content"> -->
+ <h1>%%%product.title%%%</h1>
+ <p> <span class="subtitle">%%%install.pageTitle%%%</span><br />
+ %%%install.text%%%
+ <a href="%%%console.moreInfo.url%%%" target="_blank">>>%%%console.moreInfo.linkText%%%</a></p>
+
+ <!-- don't change the names -->
+ <form id="form1" name="form1" method="post" action="%%%MYURL%%%">
+ <p> <h2>%%%connection.title%%%</h2></p>
+ <p> <input name="direct" type="radio" id="direct" tabindex="1" onclick="Javascript:checkHiddenElements(document.getElementById('direct'));" checked /><strong >%%%connection.direct%%%</strong><br> <br>
+ <input name="direct" type="radio" id="useproxy" tabindex="2" onclick="Javascript:checkHiddenElements(document.getElementById('direct'));" /><strong >%%%connection.proxy%%%</strong>
+ </p>
+ <div id="proxy" style="display:none;">
+ <div id="fields">
+ <span class="sm"><strong>%%%connection.proxy.host%%%</strong></span>
+ <input name="proxyHost" type="text" class="textInput" id="text" tabindex="3" />
+ <span class="sm"><strong >%%%connection.proxy.port%%%</strong></span>
+ <input name="pxoryPort" size="10" type="text" class="textInput" id="text2" tabindex="4" />
+ </div>
+ <div id="helptext">
+ <h4>%%%connection.helpText%%%</h4>
+ </div>
+ </div>
+ <div id="buttons">
+ <label><input type="submit" name="ok" id="ok" value="%%%button.ok%%%" tabindex="5" /></label>
+ <input type="submit" name="cancel" id="Cancel" value="%%%button.cancel%%%" tabindex="6" />
+ </div>
+ </form>
+ </div>
+ </div>
+ <div id="footer-wrapper">
+ <div id="footer">%%%thankYou%%%</div>
+ </div>
+</body>
+</html>
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/package-info.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/package-info.java
new file mode 100644
index 0000000..4b83948
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/**
+ * Provides the Grizzly Adapter functionality for the admin console
+ * application in particular. Eventually, this package should contain
+ * all admin adapter functionality.
+ * @author केदार (km@dev.java.net)
+ * @since GlassFish V3
+ */
+package com.sun.enterprise.v3.admin.adapter;
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/status.html b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/status.html
new file mode 100644
index 0000000..3ddf51f
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/status.html
@@ -0,0 +1,145 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<!--
+
+ Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v. 2.0, which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ This Source Code may also be made available under the following Secondary
+ Licenses when the conditions for such availability set forth in the
+ Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ version 2 with the GNU Classpath Exception, which is available at
+ https://www.gnu.org/software/classpath/license.html.
+
+ SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>%%%status.pageTitle%%%</title>
+
+<style type="text/css">
+a:link {color:#003399;text-decoration:none}
+a:visited {color:#003399;text-decoration:none}
+a:hover {color:#003399;text-decoration:underline}
+body {font-family:Arial,Helvetica,sans-serif;font-size:76%;margin:0px;padding:0px;background:#4a5c6a;}
+h1 {padding-top:50px;margin-top:0px;color:#46626e;font-size:21px;}
+h2 {color:#46626e;font-size:16px;}
+h4 {font-style:normal;font-size:.9em;color:#666;}
+* html body {overflow:hidden;}
+* html #footer-wrapper {float:left;position:relative;width:100%;padding-bottom:10010px;margin-bottom:-10000px;background:#4a5c6a;}
+.subtitle {color:#000000;font-size:16px;font-weight:bold;}
+.container {overflow:hidden;text-align:center;background:#d4dbe1;height:435px;}
+.container .column {text-align:left;height:435px;margin:auto;width:540px;padding-left:300px;padding-right:40px;background-image:url(/backimage.jpg);background-repeat:no-repeat;background-color:#FFFFFF;}
+.container #fields {margin-left:22px;margin-top:1em;}
+#footer {clear:both;}
+#header, #footer {font-size:small;text-align:center;padding:0.3em 0;background:#4a5c6a;height:20px;color:#FFFFFF;font-weight:bold;}
+.progress {padding-left:130px;padding-top:10px;}
+</style>
+<!--meta http-equiv="refresh" content="5;url=" /-->
+</head>
+
+ <body onLoad="document.getElementById('spin').src = '/asynch-1F.gif';">
+ <script type="text/javascript">
+ if (document.getElementById('layout-doc') != null) {
+ window.location = '%%%LOCATION%%%';
+ }
+
+
+ var feedbackZoneId = 'feedbackZone';
+
+ function start() {
+ displayCount(1,feedbackZoneId);
+
+ }
+ loaded(feedbackZoneId,start);
+
+ var pageLoaded = 0;
+
+ window.onload = function() {
+ pageLoaded = 1;
+ }
+ function loaded(i,f) {
+ if (document.getElementById && document.getElementById(i) != null) {
+ f();
+
+ }
+ else
+ if (!pageLoaded)
+ setTimeout('loaded(\''+i+'\','+f+')',100);
+ }
+
+ String.prototype.startsWith = function(s) {
+ if( this.indexOf(s) == 0 )
+ return true;
+ return false;
+ }
+
+ function displayCount(countdn,cd)
+ {
+ if (window.XMLHttpRequest)
+ {// code for IE7+, Firefox, Chrome, Opera, Safari
+ xmlhttp=new XMLHttpRequest();
+ }
+ else
+ {// code for IE6, IE5
+ xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ xmlhttp.onreadystatechange=function()
+ {
+ if (xmlhttp.readyState==4 && ((xmlhttp.status==200)||(xmlhttp.status==202)))
+ {
+ var response = ""+xmlhttp.responseText;
+ if (response.startsWith(":::")){
+ fileLines=response.split("\n");
+
+ document.getElementById("STATUS").innerHTML= fileLines[0].substring(3,fileLines[0].length);
+ document.getElementById("WELCOME").innerHTML= "<b>"+ fileLines[1]+"</b>";
+
+ /// document.getElementById(cd).innerHTML = countdn+' times ';
+ setTimeout('displayCount('+(countdn+1)+',\''+cd+'\');',999);
+ }else {
+ location.reload(true);
+ }
+ }
+ }
+ xmlhttp.open("GET","/testifbackendisready.html",true);
+ xmlhttp.send();
+
+ }
+
+</script>
+ <div id="header"></div>
+ <div class="container">
+ <div id="center" class="column">
+ <!-- <div id="page_content"> -->
+ <h1>%%%product.title%%%</h1>
+ <p>
+ <br><span id="WELCOME"> </span></p>
+ <!-- don't change the names -->
+ <form id="form1" name="form1" method="post" action="%%%MYURL%%%">
+ <p>
+ <table border="0">
+ <tbody>
+ <tr>
+ <td><img id="spin" src="/asynch-1F.gif" border="0" alt="%%%status.spin.alt%%%" /></td>
+ <td><b>%%%status.current%%%</b>
+ <span id="STATUS">%%%STATUS%%%</span></td>
+ </tr>
+ </tbody>
+ </table>
+
+ </p>
+ </form>
+ <p>
+ <br>%%%status.text%%%</p>
+ <span id="feedbackZone"></span>
+ </div>
+ </div>
+
+</body>
+</html>
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/statusNotDAS.html b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/statusNotDAS.html
new file mode 100644
index 0000000..13c2e3b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/adapter/statusNotDAS.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<!--
+
+ Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v. 2.0, which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ This Source Code may also be made available under the following Secondary
+ Licenses when the conditions for such availability set forth in the
+ Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ version 2 with the GNU Classpath Exception, which is available at
+ https://www.gnu.org/software/classpath/license.html.
+
+ SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>%%%status.pageTitle%%%</title>
+
+<style type="text/css">
+a:link {color:#003399;text-decoration:none}
+a:visited {color:#003399;text-decoration:none}
+a:hover {color:#003399;text-decoration:underline}
+body {font-family:Arial,Helvetica,sans-serif;font-size:76%;margin:0px;padding:0px;background:#4a5c6a;}
+h1 {padding-top:50px;margin-top:0px;color:#46626e;font-size:21px;}
+h2 {color:#46626e;font-size:16px;}
+h4 {font-style:normal;font-size:.9em;color:#666;}
+* html body {overflow:hidden;}
+* html #footer-wrapper {float:left;position:relative;width:100%;padding-bottom:10010px;margin-bottom:-10000px;background:#4a5c6a;}
+.subtitle {color:#000000;font-size:16px;font-weight:bold;}
+.container {overflow:hidden;text-align:center;background:#d4dbe1;height:435px;}
+.container .column {text-align:left;height:435px;margin:auto;width:540px;padding-left:300px;padding-right:40px;background-image:url(/backimage.jpg);background-repeat:no-repeat;background-color:#FFFFFF;}
+.container #fields {margin-left:22px;margin-top:1em;}
+#footer {clear:both;}
+#header, #footer {font-size:small;text-align:center;padding:0.3em 0;background:#4a5c6a;height:20px;color:#FFFFFF;font-weight:bold;}
+.progress {padding-left:130px;padding-top:10px;}
+</style>
+<meta http-equiv="refresh" content="5;url=" />
+</head>
+
+<body onLoad="document.getElementById('spin').src = '/asynch-1F.gif';">
+ <script type="text/javascript">
+ if (document.getElementById('layout-doc') != null) {
+ window.location = '%%%LOCATION%%%';
+ }
+</script>
+ <div id="header"></div>
+ <div class="container">
+ <div id="center" class="column">
+ <!-- <div id="page_content"> -->
+ <h1>%%%product.title%%%</h1>
+ <p> <span class="subtitle">%%%statusNotAvailable.pageTitle%%%</span>
+ <br>%%%statusNotAvailable.text%%%</p>
+ <!-- don't change the names -->
+ </div>
+ </div>
+ <div id="footer-wrapper">
+ <div id="footer">%%%thankYou%%%</div>
+ </div>
+</body>
+</html>
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/AttachCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/AttachCommand.java
new file mode 100644
index 0000000..0aebff9
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/AttachCommand.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.admin.remote.AdminCommandStateImpl;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import javax.inject.Inject;
+
+import com.sun.enterprise.v3.admin.JobManagerService;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.AdminCommandEventBroker.AdminCommandListener;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.admin.progress.JobInfo;
+import org.glassfish.hk2.api.PerLookup;
+
+import org.glassfish.security.services.common.SubjectUtil;
+import org.jvnet.hk2.annotations.Service;
+
+import static org.glassfish.api.admin.AdminCommandState.State.PREPARED;
+import static org.glassfish.api.admin.AdminCommandState.State.RUNNING;
+import static org.glassfish.api.admin.AdminCommandState.State.RUNNING_RETRYABLE;
+import static org.glassfish.api.admin.AdminCommandState.State.COMPLETED;
+import static org.glassfish.api.admin.AdminCommandState.State.REVERTED;
+
+
+/**
+ * Gets CommandInstance from registry based on given id and forwards all events.
+ *
+ * @author Martin Mares
+ * @author Bhakti Mehta
+ */
+@Service(name = AttachCommand.COMMAND_NAME)
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@I18n(AttachCommand.COMMAND_NAME)
+@ManagedJob
+@AccessRequired(resource="jobs/job/$jobID", action="attach")
+public class AttachCommand implements AdminCommand, AdminCommandListener {
+
+
+ public static final String COMMAND_NAME = "attach";
+ protected final static LocalStringManagerImpl strings = new LocalStringManagerImpl(AttachCommand.class);
+
+ protected AdminCommandEventBroker eventBroker;
+ protected Job attached;
+
+ @Inject
+ JobManagerService registry;
+
+ @Param(primary=true, optional=false, multiple=false)
+ protected String jobID;
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ eventBroker = context.getEventBroker();
+
+ attached = registry.get(jobID);
+ JobInfo jobInfo = null;
+ String jobName = null;
+
+ if (attached == null) {
+ //try for completed jobs
+ if (registry.getCompletedJobs(registry.getJobsFile()) != null) {
+ jobInfo = (JobInfo) registry.getCompletedJobForId(jobID);
+ }
+ if (jobInfo != null) {
+ jobName = jobInfo.jobName;
+ }
+
+ }
+
+ attach(attached,jobInfo,context,jobName);
+
+ }
+
+ @Override
+ public void onAdminCommandEvent(String name, Object event) {
+ if (name == null || name.startsWith("client.")) { //Skip nonsence or own events
+ return;
+ }
+ if (AdminCommandStateImpl.EVENT_STATE_CHANGED.equals(name) &&
+ (((Job) event).getState().equals(COMPLETED) || ((Job) event).getState().equals(REVERTED))) {
+ synchronized (attached) {
+ attached.notifyAll();
+ }
+ } else {
+ eventBroker.fireEvent(name, event); //Forward
+ }
+ }
+
+
+ protected void purgeJob(String jobid) {
+ try {
+ registry.purgeJob(jobid);
+ registry.purgeCompletedJobForId(jobid);
+ } catch (Exception ex) {
+ }
+ }
+
+ public void attach(Job attached, JobInfo jobInfo, AdminCommandContext context,String jobName) {
+ ActionReport ar = context.getActionReport();
+ String attachedUser = SubjectUtil.getUsernamesFromSubject(context.getSubject()).get(0);
+ if ((attached == null && jobInfo == null) || (attached != null && attached.getName().startsWith("_"))
+ || (attached != null && AttachCommand.COMMAND_NAME.equals(attached.getName()))) {
+ ar.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ ar.setMessage(strings.getLocalString("attach.wrong.commandinstance.id", "Job with id {0} does not exist.", jobID));
+ return;
+ }
+
+ if (attached != null) {
+ String jobInitiator = attached.getSubjectUsernames().get(0);
+ if (!attachedUser.equals( jobInitiator)) {
+ ar.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ ar.setMessage(strings.getLocalString("user.not.authorized",
+ "User {0} not authorized to attach to job {1}", attachedUser, jobID));
+ return;
+ }
+ }
+ if (attached != null) {
+ //Very sensitive locking part
+ AdminCommandEventBroker attachedBroker = attached.getEventBroker();
+ CommandProgress commandProgress = attached.getCommandProgress();
+ if (commandProgress == null) {
+ synchronized (attachedBroker) {
+ onAdminCommandEvent(AdminCommandStateImpl.EVENT_STATE_CHANGED, attached);
+ attachedBroker.registerListener(".*", this);
+ }
+ } else {
+ synchronized (commandProgress) {
+ onAdminCommandEvent(AdminCommandStateImpl.EVENT_STATE_CHANGED, attached);
+ onAdminCommandEvent(CommandProgress.EVENT_PROGRESSSTATUS_STATE, attached.getCommandProgress());
+ attachedBroker.registerListener(".*", this);
+ }
+ }
+ synchronized (attached) {
+ while(attached.getState().equals(PREPARED) ||
+ attached.getState().equals(RUNNING) ||
+ attached.getState().equals(RUNNING_RETRYABLE)) {
+ try {
+ attached.wait(1000*60*5); //5000L just to be sure
+ } catch (InterruptedException ex) {}
+ }
+ if (attached.getState().equals(COMPLETED) || attached.getState().equals(REVERTED)) {
+ String commandUser = attached.getSubjectUsernames().get(0);
+ //In most cases if the user who attaches to the command is the same
+ //as one who started it then purge the job once it is completed
+ if ((commandUser != null && commandUser.equals(attachedUser)) && attached.isOutboundPayloadEmpty()) {
+ purgeJob(attached.getId());
+
+ }
+ ar.setActionExitCode(attached.getActionReport().getActionExitCode());
+ ar.appendMessage(strings.getLocalString("attach.finished", "Command {0} executed with status {1}",attached.getName(),attached.getActionReport().getActionExitCode()));
+ }
+ }
+ } else {
+
+ if (jobInfo != null && (jobInfo.state.equals(COMPLETED.toString()) || jobInfo.state.equals(REVERTED.toString()))) {
+
+ //In most cases if the user who attaches to the command is the same
+ //as one who started it then purge the job once it is completed
+ if (attachedUser!= null && attachedUser.equals( jobInfo.user)) {
+ purgeJob(jobInfo.jobId);
+
+ }
+ ar.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ ar.appendMessage(strings.getLocalString("attach.finished", "Command {0} executed{1}",jobName,jobInfo.exitCode));
+ }
+ }
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/CLIUtil.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/CLIUtil.java
new file mode 100644
index 0000000..f5af4cd
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/CLIUtil.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.api.Target;
+
+/**
+ *
+ * @author tjquinn
+ */
+public class CLIUtil {
+
+ static Config updateConfigIfNeeded(final Config initConfig,
+ final String target,
+ final ServiceLocator locator) {
+ Target targetUtil = locator.getService(Target.class);
+ return updateConfigIfNeeded(initConfig, targetUtil, target);
+
+ }
+
+ static Config updateConfigIfNeeded(final Config initConfig,
+ final Target targetUtil,
+ final String target) {
+ Config result = initConfig;
+ Config newConfig = targetUtil.getConfig(target);
+ if (newConfig!=null) {
+ result = newConfig;
+ }
+ return result;
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ClassReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ClassReporter.java
new file mode 100644
index 0000000..9ebaf8f
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ClassReporter.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.util.i18n.StringManager;
+import java.lang.management.ClassLoadingMXBean;
+import java.lang.management.CompilationMXBean;
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServerConnection;
+
+/**
+ */
+class ClassReporter {
+
+ private final MBeanServerConnection mbsc;
+ private final StringManager sm = StringManager.getManager(ClassReporter.class);
+ public ClassReporter(final MBeanServerConnection mbsc) {
+ this.mbsc = mbsc;
+ }
+ public String getClassReport() throws RuntimeException {
+ try {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ final ClassLoadingMXBean clmb = ManagementFactory.newPlatformMXBeanProxy(mbsc,
+ ManagementFactory.CLASS_LOADING_MXBEAN_NAME, ClassLoadingMXBean.class);
+ sb.append(sm.getString("classloading.info"));
+ sb.append(sm.getString("classes.loaded", clmb.getLoadedClassCount()));
+ sb.append(sm.getString("classes.total", clmb.getTotalLoadedClassCount()));
+ sb.append(sm.getString("classes.unloaded", clmb.getUnloadedClassCount()));
+
+ final CompilationMXBean cmb = ManagementFactory.newPlatformMXBeanProxy(mbsc,
+ ManagementFactory.COMPILATION_MXBEAN_NAME, CompilationMXBean.class);
+ sb.append(sm.getString("complilation.info"));
+ sb.append(sm.getString("compilation.monitor.status", cmb.isCompilationTimeMonitoringSupported()));
+ sb.append(sm.getString("jit.compilar.name", cmb.getName()));
+ sb.append(sm.getString("compilation.time", JVMInformationCollector.millis2HoursMinutesSeconds(cmb.getTotalCompilationTime())));
+ return ( sb.toString() );
+ } catch(final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ConfigureManagedJobs.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ConfigureManagedJobs.java
new file mode 100644
index 0000000..8028cd3
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ConfigureManagedJobs.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.ManagedJobConfig;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.AccessRequired;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandLock;
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+
+import javax.inject.Inject;
+import java.beans.PropertyVetoException;
+import java.util.logging.Logger;
+import org.glassfish.kernel.KernelLoggerInfo;
+
+
+
+/**
+ * This command manages configured jobs
+ * Managed jobs are commands which are annotated with @ManagedJob ,@Progress
+ * or running with --detach
+ * You can configure the job retention period, job inactivity period,initial-delay,poll-interval
+ * persisting options for those jobs which will be used by the Job Manager
+ * to purge the jobs according to the criteria specified.
+ * Definition of parameters:
+ * job-retention-period - Time period to store the jobs. Defaults 24 hours.
+ *
+ * job-inactivity-period -Time period after which we expire an inactive, non responsive command
+ *
+ * initial-delay - Initial delay after which the cleanup service should start purging
+ * This is useful when the server restarts will provide some time for the Job Manager to
+ * bootstrap
+ *
+ * poll-interval - The time interval after which the JobCleanupService should poll for expired jobs
+ *
+
+ *
+ * @author Bhakti Mehta
+ */
+@Service(name = "configure-managed-jobs")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@AccessRequired(resource="domain/managed-job-config", action="update")
+public class ConfigureManagedJobs implements AdminCommand {
+
+ @Inject
+ Domain domain;
+
+ @Param(name="in-memory-retention-period", optional=true)
+ String inMemoryRetentionPeriod;
+
+ @Param(name="job-retention-period", optional=true)
+ String jobRetentionPeriod;
+
+ @Param(name="cleanup-initial-delay", optional=true)
+ String initialDelay;
+
+ @Param(name="cleanup-poll-interval", optional=true)
+ String pollInterval;
+
+
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ ActionReport report = context.getActionReport();
+ Logger logger= context.getLogger();
+
+ ManagedJobConfig managedJobConfig = domain.getExtensionByType(ManagedJobConfig.class);
+ if (managedJobConfig == null ) {
+ logger.warning(KernelLoggerInfo.getFailManagedJobConfig);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(KernelLoggerInfo.getLogger().getResourceBundle().getString(KernelLoggerInfo.getFailManagedJobConfig));
+ return;
+ }
+
+ try {
+ ConfigSupport.apply(new SingleConfigCode<ManagedJobConfig>() {
+
+ @Override
+ public Object run(ManagedJobConfig param) throws PropertyVetoException, TransactionFailure {
+
+ if (inMemoryRetentionPeriod != null)
+ param.setInMemoryRetentionPeriod(inMemoryRetentionPeriod);
+ if (jobRetentionPeriod != null)
+ param.setJobRetentionPeriod(jobRetentionPeriod);
+ if (pollInterval != null)
+ param.setPollInterval(pollInterval);
+ if (initialDelay != null)
+ param.setInitialDelay(initialDelay);
+
+ return param;
+ }
+ }, managedJobConfig);
+
+ } catch(TransactionFailure e) {
+ logger.warning(KernelLoggerInfo.configFailManagedJobConfig);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setMessage(e.getMessage());
+ }
+
+ }
+
+}
+
+
+
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/CreateJvmOptions.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/CreateJvmOptions.java
new file mode 100644
index 0000000..56ee05f
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/CreateJvmOptions.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import com.sun.enterprise.config.serverbeans.JvmOptionBag;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import com.sun.enterprise.util.i18n.StringManager;
+import java.beans.PropertyVetoException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.UnknownOptionsAreOperands;
+import org.glassfish.api.admin.AccessRequired;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.AdminCommandSecurity;
+import org.glassfish.api.admin.ExecuteOn;
+import org.glassfish.api.admin.RuntimeType;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+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;
+
+/**
+ * Creates given JVM options in server's configuration.
+ * @author केदार (km@dev.java.net)
+ * @author Kin-man Chung
+ * @since GlassFish V3
+ */
+
+@Service(name="create-jvm-options") //implements the cli command by this "name"
+@PerLookup //should be provided "per lookup of this class", not singleton
+@I18n("create.jvm.options")
+@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+@TargetType({CommandTarget.DAS,CommandTarget.STANDALONE_INSTANCE,CommandTarget.CLUSTER,CommandTarget.CONFIG})
+@UnknownOptionsAreOperands()
+public final class CreateJvmOptions implements AdminCommand, AdminCommandSecurity.Preauthorization {
+
+ @Param(name="target", optional=true, defaultValue = SystemPropertyConstants.DEFAULT_SERVER_INSTANCE_NAME)
+ String target;
+
+ @Param(name="profiler", optional=true)
+ Boolean addToProfiler=false;
+
+ @Param(name="jvm_option_name", primary=true, separator=':')
+ List<String> jvmOptions;
+
+ @Inject
+ Target targetService;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ private static final StringManager lsm = StringManager.getManager(ListJvmOptions.class);
+
+ @AccessRequired.To("update")
+ private JavaConfig jc;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ config = CLIUtil.updateConfigIfNeeded(config, targetService, target);
+ jc = config.getJavaConfig();
+ return true;
+ }
+
+
+ public void execute(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+ try {
+ JvmOptionBag bag;
+ if (addToProfiler) { //make sure profiler element exists before creating a JVM option for profiler
+ if (jc.getProfiler() == null) {
+ report.setMessage(lsm.getString("create.profiler.first"));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+ bag = jc.getProfiler();
+ } else
+ bag = jc;
+ ActionReport.MessagePart part = report.getTopMessagePart().addChild();
+ List<String> validOptions = new ArrayList<String>(jvmOptions);
+ validate(bag, validOptions, report); //Note: method mutates the given list
+ validateSoft(bag, validOptions, report); //Note: method does not mutate the given list
+ addX(bag, validOptions, part);
+ } catch (IllegalArgumentException iae) {
+ report.setMessage(iae.getMessage());
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ } catch (Exception e) {
+ String msg = e.getMessage() != null ? e.getMessage() :
+ lsm.getStringWithDefault("create.jvm.options.failed",
+ "Command: create-jvm-options failed", new String[]{e.getMessage()});
+ report.setMessage(msg);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ return;
+ }
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+
+ private void validateSoft(JvmOptionBag bag, List<String> opts, ActionReport report) {
+ //Note: These are only recommendations!
+ Iterator<String> siter = opts.iterator();
+ while (siter.hasNext()) {
+ String opt = siter.next();
+ validateSoftXmx(bag, opt, report);
+ validateSoftXms(bag, opt, report);
+ }
+ }
+
+ private void validateSoftXmx(JvmOptionBag bag, String opt, ActionReport report) {
+ if (!opt.startsWith("-Xmx"))
+ return;
+ //now, opt is something like -Xmx512m or -Xmx2g, or -Xmx=12 i.e. it may contain illegal characters
+ try {
+ Pattern regex = Pattern.compile("-Xmx((\\d)+[m|g|k|M|G|K]?)+");
+ boolean matches = regex.matcher(opt).matches();
+ if (!matches) {
+ String msg = lsm.getString("soft.invalid.xmx", opt);
+ report.getTopMessagePart().addChild().setMessage(msg);
+ }
+ } catch(Exception e) {
+ //squelch
+ //e.printStackTrace();
+ }
+ String existingXmx = bag.getStartingWith("-Xmx");
+ if (existingXmx != null) {
+ //maybe a different Xmx was given
+ String msg = lsm.getString("soft.xmx.exists", existingXmx);
+ report.getTopMessagePart().addChild().setMessage(msg);
+ }
+ String existingXms = bag.getStartingWith("-Xms");
+ if (existingXms != null) {
+ int xmsInConfig = JvmOptionBag.Duck.toMeg(existingXms, "-Xms");
+ int xmxGiven = JvmOptionBag.Duck.toMeg(opt, "-Xmx");
+ if (xmsInConfig > xmxGiven) { //i.e. domain.xml contains -Xms1g and you ask -Xmx512m to be set
+ String msg = lsm.getString("soft.xmx.smaller.than.xms", xmxGiven + " MB", xmsInConfig + " MB");
+ report.getTopMessagePart().addChild().setMessage(msg);
+ }
+ }
+ }
+
+ private void validateSoftXms(JvmOptionBag bag, String opt, ActionReport report) {
+ if (!opt.startsWith("-Xms"))
+ return;
+ //now, opt is something like -Xms512m or -Xms2g, or -Xms=12 i.e. it may contain illegal characters
+ try {
+ Pattern regex = Pattern.compile("-Xms((\\d)+[m|g|k|M|G|K]?)+");
+ boolean matches = regex.matcher(opt).matches();
+ if (!matches) {
+ String msg = lsm.getString("soft.invalid.xms", opt);
+ report.getTopMessagePart().addChild().setMessage(msg);
+ }
+ } catch(Exception e) {
+ //squelch
+ //e.printStackTrace();
+ }
+ String existingXms = bag.getStartingWith("-Xms");
+ if (existingXms != null) {
+ //maybe a different Xmx was given
+ String msg = lsm.getString("soft.xms.exists", existingXms);
+ report.getTopMessagePart().addChild().setMessage(msg);
+ }
+ String existingXmx = bag.getStartingWith("-Xmx");
+ if (existingXmx != null) {
+ int xmxInConfig = JvmOptionBag.Duck.toMeg(existingXmx, "-Xmx");
+ int xmsGiven = JvmOptionBag.Duck.toMeg(opt, "-Xms");
+ if (xmsGiven > xmxInConfig) { //i.e. domain.xml contains -Xms1g and you ask -Xmx512m to be set
+ String msg = lsm.getString("soft.xms.larger.than.xmx", xmsGiven + " MB", xmxInConfig + " MB");
+ report.getTopMessagePart().addChild().setMessage(msg);
+ }
+ }
+ }
+
+ private void validate(JvmOptionBag bag, List<String> opts, ActionReport report)
+ throws IllegalArgumentException {
+ Iterator<String> siter = opts.iterator();
+ while (siter.hasNext()) {
+ String opt = siter.next();
+ if (!opt.startsWith("-")) {
+ String msg = lsm.getString("joe.invalid.start", opt);
+ throw new IllegalArgumentException(msg);
+ }
+ if (bag.contains(opt)) {
+ // setting an option that already exists is considered an error
+ String msg = lsm.getString("joe.exists", opt);
+ throw new IllegalArgumentException(msg);
+ }
+ }
+ }
+
+ /** Adds the JVM option transactionally.
+ * @throws java.lang.Exception
+ */
+ // following should work in the fullness of time ...
+ /*
+ private static void addX(JavaConfig jc, final String option) throws Exception {
+ SingleConfigCode<JavaConfig> scc = new SingleConfigCode<JavaConfig> () {
+ public Object run(JavaConfig jc) throws PropertyVetoException, TransactionFailure {
+ List<String> jvmopts = jc.getJvmOptions();
+ jvmopts.add(option);
+ return ( jc.getJvmOptions() );
+ }
+ };
+ ConfigSupport.apply(scc, jc);
+ }
+ */
+ //@ForTimeBeing :)
+ private void addX(final JvmOptionBag bag, final List<String> newOpts, final ActionReport.MessagePart part) throws Exception {
+ SingleConfigCode<JvmOptionBag> scc = new SingleConfigCode<JvmOptionBag> () {
+ public Object run(JvmOptionBag bag) throws PropertyVetoException, TransactionFailure {
+ newOpts.removeAll(bag.getJvmOptions()); //"prune" the given list first to avoid duplicates
+ List<String> jvmopts = new ArrayList<String>(bag.getJvmOptions());
+ int orig = jvmopts.size();
+ boolean added = jvmopts.addAll(newOpts);
+ bag.setJvmOptions(jvmopts);
+ int now = jvmopts.size();
+ if (added) {
+ part.setMessage(lsm.getString("created.message", (now-orig)));
+ } else {
+ part.setMessage(lsm.getString("no.option.created"));
+ }
+ return true;
+ }
+ };
+ ConfigSupport.apply(scc, bag);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/CreateThreadpool.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/CreateThreadpool.java
new file mode 100644
index 0000000..c452f7d
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/CreateThreadpool.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import java.beans.PropertyVetoException;
+
+import org.glassfish.internal.api.Target;
+import com.sun.enterprise.config.serverbeans.*;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.ActionReport;
+
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+
+import org.glassfish.grizzly.config.dom.ThreadPool;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.SystemPropertyConstants;
+
+
+/**
+ * Create Thread Pool Command
+ *
+ */
+@Service(name="create-threadpool")
+@PerLookup
+@I18n("create.threadpool")
+@org.glassfish.api.admin.ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+@TargetType({CommandTarget.DAS,CommandTarget.STANDALONE_INSTANCE,CommandTarget.CLUSTER,CommandTarget.CONFIG})
+
+public class CreateThreadpool implements AdminCommand, AdminCommandSecurity.Preauthorization {
+
+ final private static LocalStringManagerImpl localStrings = new
+ LocalStringManagerImpl(CreateThreadpool.class);
+
+ // TODO: Once Grizzly provides constants for default values, update this class to use those
+ // constants: https://grizzly.dev.java.net/issues/show_bug.cgi?id=897 -- jdlee
+ @Param(name="maxthreadpoolsize", optional=true, alias="maxThreadPoolSize", defaultValue = "5")
+ String maxthreadpoolsize;
+
+ @Param(name="minthreadpoolsize", optional=true, alias="minThreadPoolSize", defaultValue = "2")
+ String minthreadpoolsize;
+
+ @Param(name= "idletimeout", optional=true, alias="idleThreadTimeoutSeconds", defaultValue = "900")
+ String idletimeout;
+
+ @Param(name="workqueues", optional=true)
+ String workqueues;
+
+ @Param(name="maxqueuesize", optional=true, alias="maxQueueSize", defaultValue = "4096")
+ String maxQueueSize;
+
+ @Param(name = "target", optional = true, defaultValue = SystemPropertyConstants.DEFAULT_SERVER_INSTANCE_NAME)
+ String target;
+
+ @Param(name="threadpool_id", primary=true)
+ String threadpool_id;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ @Inject
+ Domain domain;
+
+ @Inject
+ ServiceLocator habitat;
+
+ @AccessRequired.NewChild(type=ThreadPool.class)
+ private ThreadPools threadPools;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ config = CLIUtil.updateConfigIfNeeded(config, target, habitat);
+ threadPools = config.getThreadPools();
+ for (ThreadPool pool: threadPools.getThreadPool()) {
+ final ActionReport report = context.getActionReport();
+ if (pool.getName().equals(threadpool_id)) {
+ report.setMessage(localStrings.getLocalString("create.threadpool.duplicate",
+ "Thread Pool named {0} already exists.", threadpool_id));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * Executes the command with the command parameters passed as Properties
+ * where the keys are the paramter names and the values the parameter values
+ *
+ * @param context information
+ */
+
+ public void execute(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+ if (workqueues != null) {
+ report.setMessage(localStrings.getLocalString("create.threadpool.deprecated.workqueues",
+ "Deprecated Syntax: --workqueues option is deprecated for create-threadpool command."));
+ }
+
+ try {
+ ConfigSupport.apply(new SingleConfigCode<ThreadPools>() {
+ public Object run(ThreadPools param) throws PropertyVetoException, TransactionFailure {
+ ThreadPool newPool = param.createChild(ThreadPool.class);
+ newPool.setName(threadpool_id);
+ newPool.setMaxThreadPoolSize(maxthreadpoolsize);
+ newPool.setMinThreadPoolSize(minthreadpoolsize);
+ newPool.setMaxQueueSize(maxQueueSize);
+ newPool.setIdleThreadTimeoutSeconds(idletimeout);
+ param.getThreadPool().add(newPool);
+ return newPool;
+ }
+ }, threadPools);
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ } catch (TransactionFailure e) {
+ String str = e.getMessage();
+ String def = "Creation of: " + threadpool_id + "failed because of: " + str;
+ String msg = localStrings.getLocalString("create.threadpool.failed", def, threadpool_id, str);
+ report.setMessage(msg);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/DeleteJvmOptions.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/DeleteJvmOptions.java
new file mode 100644
index 0000000..b113d00
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/DeleteJvmOptions.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import com.sun.enterprise.config.serverbeans.JvmOptionBag;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import com.sun.enterprise.util.i18n.StringManager;
+import java.beans.PropertyVetoException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.UnknownOptionsAreOperands;
+import org.glassfish.api.admin.AccessRequired;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.AdminCommandSecurity;
+import org.glassfish.api.admin.ExecuteOn;
+import org.glassfish.api.admin.RuntimeType;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+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;
+
+/**
+ * Deletes given JVM options in server's configuration.
+ * @author केदार (km@dev.java.net)
+ * @author Kin-man Chung
+ * @since GlassFish V3
+ */
+@Service(name="delete-jvm-options") //implements the cli command by this "name"
+@PerLookup //should be provided "per lookup of this class", not singleton
+@I18n("delete.jvm.options")
+@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+@TargetType({CommandTarget.DAS,CommandTarget.STANDALONE_INSTANCE,CommandTarget.CLUSTER,CommandTarget.CONFIG})
+@UnknownOptionsAreOperands()
+public final class DeleteJvmOptions implements AdminCommand, AdminCommandSecurity.Preauthorization {
+
+ @Param(name="target", optional=true, defaultValue = SystemPropertyConstants.DEFAULT_SERVER_INSTANCE_NAME)
+ String target;
+
+ @Param(name="profiler", optional=true)
+ Boolean fromProfiler = false;
+
+ @Param(name="jvm_option_name", primary=true, separator=':')
+ List<String> jvmOptions;
+
+ @Inject
+ Target targetService;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ private static final StringManager lsm = StringManager.getManager(ListJvmOptions.class);
+
+ @AccessRequired.To("update")
+ private JavaConfig jc;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ config = CLIUtil.updateConfigIfNeeded(config, targetService, target);
+ jc = config.getJavaConfig();
+ return true;
+ }
+
+ public void execute(AdminCommandContext context) {
+ //validate the target first
+ final ActionReport report = context.getActionReport();
+
+ try {
+ JvmOptionBag bag;
+ if (fromProfiler) {
+ if (jc.getProfiler() == null) {
+ report.setMessage(lsm.getString("create.profiler.first"));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+ bag = jc.getProfiler();
+ } else
+ bag = jc;
+ ActionReport.MessagePart part = report.getTopMessagePart().addChild();
+ deleteX(bag, jvmOptions, part);
+ } catch (Exception e) {
+ String msg = e.getMessage() != null ? e.getMessage() :
+ lsm.getStringWithDefault("delete.jvm.options.failed",
+ "Command: delete-jvm-options failed", new String[]{e.getMessage()});
+ report.setMessage(msg);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ return;
+ }
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+
+
+ /** Adds the JVM option transactionally.
+ * @throws java.lang.Exception
+ */
+ // following should work in the fullness of time ...
+ /*
+ private static void addX(JavaConfig jc, final String option) throws Exception {
+ SingleConfigCode<JavaConfig> scc = new SingleConfigCode<JavaConfig> () {
+ public Object run(JavaConfig jc) throws PropertyVetoException, TransactionFailure {
+ List<String> jvmopts = jc.getJvmOptions();
+ jvmopts.add(option);
+ return ( jc.getJvmOptions() );
+ }
+ };
+ ConfigSupport.apply(scc, jc);
+ }
+ */
+ //@ForTimeBeing :)
+ private void deleteX(final JvmOptionBag bag, final List<String> toRemove, final ActionReport.MessagePart part) throws Exception {
+ SingleConfigCode<JvmOptionBag> scc = new SingleConfigCode<JvmOptionBag> () {
+ public Object run(JvmOptionBag bag) throws PropertyVetoException, TransactionFailure {
+ List<String> jvmopts = new ArrayList<String>(bag.getJvmOptions());
+ int orig = jvmopts.size();
+ boolean removed = jvmopts.removeAll(toRemove);
+ bag.setJvmOptions(jvmopts);
+ int now = jvmopts.size();
+ if (removed) {
+ part.setMessage(lsm.getString("deleted.message", (orig-now)));
+ } else {
+ part.setMessage(lsm.getString("no.option.deleted"));
+ }
+ return true;
+ }
+ };
+ ConfigSupport.apply(scc, bag);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/DeleteThreadpool.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/DeleteThreadpool.java
new file mode 100644
index 0000000..f0382e2
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/DeleteThreadpool.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import java.beans.PropertyVetoException;
+import java.util.List;
+
+import org.glassfish.internal.api.Target;
+import com.sun.enterprise.config.serverbeans.*;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.ActionReport;
+
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+
+import org.glassfish.grizzly.config.dom.ThreadPool;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.grizzly.config.dom.Protocol;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import org.glassfish.api.ActionReport.ExitCode;
+
+@Service(name="delete-threadpool")
+@PerLookup
+@I18n("delete.threadpool")
+@org.glassfish.api.admin.ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE})
+@TargetType({CommandTarget.DAS,CommandTarget.STANDALONE_INSTANCE,CommandTarget.CLUSTER,CommandTarget.CONFIG})
+public class DeleteThreadpool implements AdminCommand, AdminCommandSecurity.Preauthorization {
+
+ final private static LocalStringManagerImpl localStrings =
+ new LocalStringManagerImpl(DeleteThreadpool.class);
+
+ @Param(name="threadpool_id", primary=true)
+ String threadpool_id;
+
+ @Param(name = "target", optional = true, defaultValue = SystemPropertyConstants.DEFAULT_SERVER_INSTANCE_NAME)
+ String target;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ @Inject
+ Configs configs;
+
+ @Inject
+ Domain domain;
+
+ @Inject
+ ServiceLocator habitat;
+
+ private ThreadPools threadPools;
+
+ @AccessRequired.To("delete")
+ private ThreadPool pool;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+ config = CLIUtil.updateConfigIfNeeded(config, target, habitat);
+ threadPools = config.getThreadPools();
+ if(!isThreadPoolExists(threadPools)) {
+ report.setMessage(localStrings.getLocalString("delete.threadpool.notexists",
+ "Thread Pool named {0} does not exist.", threadpool_id));
+ report.setActionExitCode(ExitCode.FAILURE);
+ return false;
+ }
+ pool = null;
+ for (ThreadPool tp : config.getThreadPools().getThreadPool()) {
+ if (tp.getName().equals(threadpool_id)) {
+ pool = tp;
+ }
+ }
+
+ List<NetworkListener> nwlsnrList = pool.findNetworkListeners();
+ for (NetworkListener nwlsnr : nwlsnrList) {
+ if (pool.getName().equals(nwlsnr.getThreadPool())) {
+ report.setMessage(localStrings.getLocalString(
+ "delete.threadpool.beingused",
+ "{0} threadpool is being used in the network listener {1}",
+ threadpool_id, nwlsnr.getName()));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+
+ /**
+ * Executes the command with the command parameters passed as Properties
+ * where the keys are the paramter names and the values the parameter values
+ *
+ * @param context information
+ */
+ public void execute(AdminCommandContext context) {
+ ActionReport report = context.getActionReport();
+
+
+
+ try {
+ ConfigSupport.apply(new SingleConfigCode<ThreadPools>() {
+ public Object run(ThreadPools param) throws PropertyVetoException,
+ TransactionFailure {
+ List<ThreadPool> poolList = param.getThreadPool();
+ for (ThreadPool pool : poolList) {
+ String currPoolId = pool.getName();
+ if (currPoolId != null && currPoolId.equals
+ (threadpool_id)) {
+ poolList.remove(pool);
+ break;
+ }
+ }
+ return poolList;
+ }
+ }, threadPools);
+ report.setActionExitCode(ExitCode.SUCCESS);
+ } catch(TransactionFailure e) {
+ String str = e.getMessage();
+ report.setMessage(localStrings.getLocalString("delete.threadpool" +
+ ".failed", "Delete Thread Pool failed because of: ", str));
+ report.setActionExitCode(ExitCode.FAILURE);
+ report.setFailureCause(e);
+ }
+ }
+
+ private boolean isThreadPoolExists(ThreadPools threadPools) {
+
+ for (ThreadPool pool : threadPools.getThreadPool()) {
+ String currPoolId = pool.getName();
+ if (currPoolId != null && currPoolId.equals(threadpool_id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/GenerateJvmReportCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/GenerateJvmReportCommand.java
new file mode 100644
index 0000000..4fe2923
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/GenerateJvmReportCommand.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.config.serverbeans.Cluster;
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import com.sun.enterprise.config.serverbeans.Server;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.ActionReport.ExitCode;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PerLookup;
+
+import javax.management.MBeanServer;
+import java.lang.management.ManagementFactory;
+import org.glassfish.api.admin.*;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+
+/** Implements the front end for generating the JVM report. Sends back a String
+ * to the asadmin console based on server's locale.
+ * @author केदार (km@dev.java.net)
+ * @since GlassFish V3
+ */
+@Service(name="generate-jvm-report")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("generate.jvm.report")
+@TargetType({CommandTarget.DAS, CommandTarget.STANDALONE_INSTANCE, CommandTarget.CLUSTERED_INSTANCE})
+@ExecuteOn(value = {RuntimeType.INSTANCE}, ifNeverStarted=FailurePolicy.Error)
+@RestEndpoints({
+ @RestEndpoint(configBean=Cluster.class,
+ opType=RestEndpoint.OpType.GET,
+ path="generate-jvm-report",
+ description="Generate Report",
+ params={
+ @RestParam(name="target", value="$parent")
+ }),
+ @RestEndpoint(configBean=Server.class,
+ opType=RestEndpoint.OpType.GET,
+ path="generate-jvm-report",
+ description="Generate Report",
+ params={
+ @RestParam(name="target", value="$parent")
+ }),
+ @RestEndpoint(configBean=JavaConfig.class,
+ opType=RestEndpoint.OpType.GET,
+ path="generate-jvm-report",
+ description="Generate Report",
+ params={
+ @RestParam(name="target", value="$grandparent")
+ })
+})
+@AccessRequired(resource="domain/jvm", action="read")
+public class GenerateJvmReportCommand implements AdminCommand {
+
+ @Param(name="target", optional=true)
+ String target;
+
+ @Param(name="type", optional=true, defaultValue="summary",
+ acceptableValues = "summary, thread, class, memory, log")
+ String type;
+
+ private MBeanServer mbs = null; //needs to be injected, I guess
+
+ public void execute(AdminCommandContext ctx) {
+ prepare();
+ String result = getResult();
+ ActionReport report = ctx.getActionReport();
+ report.setMessage(result);
+ report.setActionExitCode(ExitCode.SUCCESS);
+ }
+
+ private synchronized void prepare() {
+ mbs = ManagementFactory.getPlatformMBeanServer();
+ }
+ private String getResult() {
+ if (type.equals("summary"))
+ return new SummaryReporter(mbs).getSummaryReport();
+ else if (type.equals("thread"))
+ return new ThreadMonitor(mbs).getThreadDump();
+ else if (type.equals("class"))
+ return new ClassReporter(mbs).getClassReport();
+ else if (type.equals("memory"))
+ return new MemoryReporter(mbs).getMemoryReport();
+ else if (type.equals("log"))
+ return new LogReporter().getLoggingReport();
+ else
+ throw new IllegalArgumentException("Unsupported Option: " + type); //this should not happen
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/GetPayloadCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/GetPayloadCommand.java
new file mode 100644
index 0000000..e88dd0d
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/GetPayloadCommand.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import javax.inject.Inject;
+import org.glassfish.admin.payload.PayloadImpl;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.admin.Payload.Outbound;
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.annotations.Service;
+
+/** Retrieve outbound payload from finished managed job.
+ *
+ * @author mmares
+ */
+@Service(name = "_get-payload")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("getpayload")
+@AccessRequired(resource="jobs/job/$jobID", action="read")
+public class GetPayloadCommand implements AdminCommand {
+
+ private final static LocalStringManagerImpl strings = new LocalStringManagerImpl(GetPayloadCommand.class);
+
+ @Inject
+ JobManager registry;
+
+ @Param(primary=true, optional=false, multiple=false)
+ String jobID;
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ ActionReport ar = context.getActionReport();
+ Job job = registry.get(jobID);
+ if (job == null) {
+ ar.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ ar.setMessage(strings.getLocalString("getPayload.wrong.commandinstance.id", "Command instance {0} does not exist.", jobID));
+ return;
+ }
+ Outbound jobPayload = job.getPayload();
+ if (jobPayload == null) {
+ ar.setMessage(strings.getLocalString("getPayload.nopayload", "Outbound payload does not exist."));
+ return; //Just return. This is OK.
+ }
+ Outbound paylaod = context.getOutboundPayload();
+ if ((paylaod instanceof PayloadImpl.Outbound) && (jobPayload instanceof PayloadImpl.Outbound)) {
+ PayloadImpl.Outbound destination = (PayloadImpl.Outbound) paylaod;
+ PayloadImpl.Outbound source = (PayloadImpl.Outbound) jobPayload;
+ destination.getParts().addAll(source.getParts());
+ } else {
+ ar.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ ar.setMessage(strings.getLocalString("getPayload.unsupported", "Payload type is not supported. Can not download data."));
+ }
+
+ }
+
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/JVMInformation.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/JVMInformation.java
new file mode 100644
index 0000000..8c0b3b1
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/JVMInformation.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import javax.management.MBeanServerConnection;
+
+/**
+ */
+public class JVMInformation implements JVMInformationMBean { //, MBeanRegistration TODO
+ private final MBeanServerConnection mbsc;
+ private final ThreadMonitor tm;
+ private final SummaryReporter sr;
+ private final MemoryReporter mr;
+ private final ClassReporter cr;
+ private final LogReporter lr;
+
+ public JVMInformation(MBeanServerConnection mbsc) {
+ this.mbsc = mbsc;
+ tm = new ThreadMonitor(mbsc);
+ sr = new SummaryReporter(mbsc);
+ mr = new MemoryReporter(mbsc);
+ cr = new ClassReporter(mbsc);
+ lr = new LogReporter();
+ }
+ public String getThreadDump(final String processName) {
+ return ( tm.getThreadDump() );
+ }
+
+ public String getSummary(final String processName) {
+ return ( sr.getSummaryReport() );
+ }
+
+ public String getMemoryInformation(final String processName) {
+ return ( mr.getMemoryReport() );
+ }
+
+ public String getClassInformation(final String processName) {
+ return ( cr.getClassReport() );
+ }
+
+ public String getLogInformation(final String processName) {
+ return (lr.getLoggingReport());
+ }
+ /* //TODO
+ public void postRegister(Boolean registrationDone) {
+ }
+
+ public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
+ this.mbsc = server;
+ final String sn = System.getProperty(SystemPropertyConstants.SERVER_NAME);
+ final ObjectName on = JVMInformationCollector.formObjectName(sn, JVMInformation.class.getSimpleName());
+ return ( on );
+ }
+
+ public void preDeregister() throws Exception {
+ }
+
+ public void postDeregister() {
+ }
+ */
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/JVMInformationCollector.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/JVMInformationCollector.java
new file mode 100644
index 0000000..7b27f16
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/JVMInformationCollector.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.util.SystemPropertyConstants;
+import com.sun.enterprise.util.i18n.StringManager;
+import java.text.NumberFormat;
+import java.util.Hashtable;
+import javax.management.*;
+
+/**
+ */
+public class JVMInformationCollector extends StandardMBean implements JVMInformationMBean {
+
+ static final String SERVER_NAME_KEY_IN_ON = "server"; // the key to identify the server
+ private MBeanServerConnection mbsc;
+ private static final StringManager sm = StringManager.getManager(JVMInformationCollector.class);
+ public JVMInformationCollector() throws NotCompliantMBeanException {
+ super(JVMInformationMBean.class);
+ }
+ @Override
+ public String getThreadDump(final String processName) {
+ final ObjectName on = processTarget(processName);
+ final String title = sm.getString("thread.dump.title", getInstanceNameFromObjectName(on));
+ final String td = title + "\n" + invokeMBean(on, "getThreadDump");
+ return ( td );
+ }
+
+ @Override
+ public String getSummary(final String processName) {
+ final ObjectName on = processTarget(processName);
+ final String title = sm.getString("summary.title", getInstanceNameFromObjectName(on));
+ final String s = title + "\n" + invokeMBean(on, "getSummary");
+ return ( s );
+ }
+
+ @Override
+ public String getMemoryInformation(final String processName) {
+ final ObjectName on = processTarget(processName);
+ final String title = sm.getString("memory.info.title", getInstanceNameFromObjectName(on));
+ final String mi = title + "\n" + invokeMBean(on, "getMemoryInformation");
+ return ( mi );
+ }
+
+ @Override
+ public String getClassInformation(final String processName) {
+ final ObjectName on = processTarget(processName);
+ final String title = sm.getString("class.info.title", getInstanceNameFromObjectName(on));
+ final String ci = title + "\n " + invokeMBean(on, "getClassInformation");
+ return ( ci );
+ }
+ @Override
+ public String getLogInformation(String processName) {
+ ObjectName on = processTarget(processName);
+ String title = sm.getString("log.info.title", getInstanceNameFromObjectName(on));
+ String li = title + "\n" + invokeMBean(on, "getLogInformation");
+ return ( li );
+ }
+
+ private ObjectName processTarget(final String processName) throws RuntimeException {
+ try {
+ //get the object-name of the "other" real implementation of JVMInformationMBean interface :)
+ final String sn = processName == null ? SERVER_NAME_KEY_IN_ON : processName;
+ final String cn = JVMInformation.class.getSimpleName();
+ final ObjectName on = formObjectName(sn, cn);
+ if (! this.mbsc.isRegistered(on)) {
+ final String msg = sm.getString("server.unreachable", sn);
+ throw new RuntimeException(msg);
+ }
+ return (on);
+ } catch (final RuntimeException re) {
+ throw(re);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String invokeMBean(final ObjectName jvm, final String method) throws RuntimeException {
+ try {
+ //though proxies work fine, for now (jul 2005/8), I am not going to use them because I am not sure how they work with cascading
+ //it is okay to assume that the methods in this mbean take String as parameter
+ final Object[] params = {null};
+ final String[] sign = {"java.lang.String"};
+ final Object ret = this.mbsc.invoke(jvm, method, params, sign);
+
+ return ( (String) ret );
+
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ @Override
+ public void postRegister(Boolean registrationDone) {
+ }
+
+ @Override
+ public ObjectName preRegister(final MBeanServer server, final ObjectName name) throws Exception {
+ this.mbsc = server;
+ final String sn = System.getProperty(SystemPropertyConstants.SERVER_NAME);
+ final ObjectName on = formObjectName(sn, JVMInformationCollector.class.getSimpleName());
+ return ( on );
+ }
+
+ @Override
+ public void preDeregister() throws Exception {
+ }
+
+ @Override
+ public void postDeregister() {
+ }
+
+ /* package private */ static ObjectName formObjectName(final String sn, final String cName) throws Exception {
+ /* domain:type=impl-class,server=target-server*/
+ final String domain = "amx-internal";
+ final Hashtable<String, String> props = new Hashtable<String, String> ();
+ props.put("type", cName);
+ props.put("category", "monitor");
+ final String snk = SERVER_NAME_KEY_IN_ON;
+ props.put(snk, sn);
+ return ( new ObjectName(domain, props) );
+ }
+
+ private String getInstanceNameFromObjectName(ObjectName on) {
+ return ( on.getKeyProperty(SERVER_NAME_KEY_IN_ON) );
+ }
+
+ static String millis2HoursMinutesSeconds(final long millis) {
+ final long secmin = millis / (long) 1000;
+ final long sec = secmin % 60;
+ final long minhr = secmin / 60;
+ final long min = minhr % 60;
+ final long hr = minhr / 60;
+ final String msg = sm.getString("m2hms", hr, min, sec);
+
+ return ( msg );
+ }
+ static String millis2SecondsMillis(final long millis) {
+ final long sec = millis / (long) 1000;
+ final long ms = millis % 1000;
+ final String msg = sm.getString("m2sms", sec, ms);
+ return ( msg );
+ }
+ static String formatLong(final long sayBytes) {
+ final NumberFormat n = NumberFormat.getInstance();
+ return ( n.format(sayBytes) );
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/JVMInformationMBean.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/JVMInformationMBean.java
new file mode 100644
index 0000000..0914579
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/JVMInformationMBean.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+/** An interface to get the information about the JVM which the appserver is running.
+ * This interface is intended to replace the traditional techniques to get thread
+ * dump from a JVM. This is the interface of the MBean that will implement the
+ * JMX based techniques in JDK 1.5+ platform to get interesting information about
+ * the JVM itself.
+ */
+public interface JVMInformationMBean {
+
+ public String getThreadDump(String processName);
+
+ public String getClassInformation(String processName);
+
+ public String getMemoryInformation(String processName);
+
+ public String getSummary(String processName);
+
+ public String getLogInformation(String processName);
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ListJobsCommand.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ListJobsCommand.java
new file mode 100644
index 0000000..b8015a4
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ListJobsCommand.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+import com.sun.enterprise.admin.progress.ProgressStatusClient;
+import com.sun.enterprise.util.StringUtils;
+import com.sun.enterprise.util.i18n.StringManager;
+import com.sun.enterprise.v3.admin.JobAuthorizationAttributeProcessor;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.Collection;
+import java.util.Date;
+import javax.inject.Inject;
+
+import com.sun.enterprise.v3.admin.JobManagerService;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.ActionReport.MessagePart;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import org.glassfish.api.admin.progress.JobInfo;
+import org.glassfish.api.admin.progress.JobInfos;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.security.services.common.SubjectUtil;
+import org.jvnet.hk2.annotations.Service;
+
+
+/**
+ * This command will list the jobs related information
+ * Currently it prints the jobId, name, time of execution,user and the state
+ *
+ * @author Bhakti Mehta
+ */
+@Service(name="list-jobs")
+@PerLookup
+@I18n("list-jobs")
+public class ListJobsCommand implements AdminCommand,AdminCommandSecurity.AccessCheckProvider {
+
+ private ActionReport report;
+ private static final String DEFAULT_USER_STRING = "-";
+
+ @Inject
+ private JobManagerService jobManagerService;
+
+ /**
+ * Associates an access check with each candidate JobInfo we might report on.
+ */
+ private final Collection<AccessRequired.AccessCheck<JobInfo>> jobAccessChecks = new ArrayList<AccessRequired.AccessCheck<JobInfo>>();
+
+ private final String JOBS_FILE = "jobs.xml";
+
+ @Param(optional = true, primary = true)
+ String jobID;
+
+ @Inject
+ private ServerEnvironment serverEnvironment;
+
+ protected static final String TITLE_NAME = "NAME";
+ protected static final String TITLE_JOBID = "JOB ID";
+ protected static final String TITLE_TIME = "TIME";
+ protected static final String TITLE_STATE = "STATE";
+ protected static final String TITLE_EXITCODE = "EXIT CODE";
+ protected static final String TITLE_USER = "USER";
+ protected static final String TITLE_NONE = "Nothing to list.";
+ public static final String NAME = "jobName";
+ public static final String ID = "jobId";
+ public static final String DATE = "executionDate";
+ public static final String CODE = "exitCode";
+ public static final String USER = "user";
+ public static final String STATE = "jobState";
+ public static final String MESSAGE = "message";
+ public static final String COMPLETION_DATE = "completionDate";
+
+
+ final private static StringManager localStrings =
+ StringManager.getManager(ListJobsCommand.class);
+
+ protected JobInfos getCompletedJobs() {
+ return jobManagerService.getCompletedJobs(jobManagerService.getJobsFile());
+ }
+
+ protected JobInfo getCompletedJobForId(final String jobID) {
+ return (JobInfo) jobManagerService.getCompletedJobForId(jobID);
+ }
+
+ protected boolean isSingleJobOK(final Job singleJob) {
+ return (singleJob != null);
+ }
+
+ protected boolean isJobEligible(final Job job) {
+ return !skipJob(job.getName()) && checkScope(job);
+ }
+
+ protected boolean checkScope(Job job) {
+ return job.getScope()==null;
+ }
+
+ private List<JobInfo> chooseJobs() {
+ List<JobInfo> jobsToReport = new ArrayList<JobInfo>();
+
+ if (jobID != null) {
+ Job oneJob = jobManagerService.get(jobID);
+ JobInfo info = null;
+
+ if (isSingleJobOK(oneJob)) {
+ List<String> userList = oneJob.getSubjectUsernames();
+ ActionReport actionReport = oneJob.getActionReport();
+ String message = actionReport == null ? "" : actionReport.getMessage();
+
+ if (!StringUtils.ok(message)) {
+ message = ProgressStatusClient.composeMessageForPrint(oneJob.getCommandProgress());
+ }
+ String exitCode = actionReport == null ? "" : actionReport.getActionExitCode().name();
+ info = new JobInfo(oneJob.getId(),oneJob.getName(),oneJob.getCommandExecutionDate(),exitCode,userList.get(0),message,oneJob.getJobsFile(),oneJob.getState().name(),0);
+
+ } else {
+ if (getCompletedJobs() != null) {
+ info = getCompletedJobForId(jobID);
+ }
+ }
+
+ if (info != null && !skipJob(info.jobName)) {
+ jobsToReport.add(info);
+ }
+
+ } else {
+
+ for (Iterator<Job> iterator = jobManagerService.getJobs(); iterator.hasNext(); ) {
+ Job job = iterator.next();
+ if (isJobEligible(job)) {
+ List<String> userList = job.getSubjectUsernames();
+ ActionReport actionReport = job.getActionReport();
+
+ String message = actionReport == null ? "" : actionReport.getMessage();
+ if (!StringUtils.ok(message)) {
+ message = ProgressStatusClient.composeMessageForPrint(job.getCommandProgress());
+ }
+ String exitCode = actionReport == null ? "" : actionReport.getActionExitCode().name();
+
+ String user = DEFAULT_USER_STRING;
+ if(userList.size() > 0){
+ user = userList.get(0);
+ }
+ jobsToReport.add(new JobInfo(job.getId(),job.getName(),job.getCommandExecutionDate(),exitCode,user,message,job.getJobsFile(),job.getState().name(),0));
+ }
+ }
+
+ JobInfos completedJobs = getCompletedJobs();
+ if (completedJobs != null ) {
+ for (JobInfo info : completedJobs.getJobInfoList()) {
+ if (!skipJob(info.jobName)) {
+ jobsToReport.add(info);
+ }
+ }
+ }
+ }
+ return jobsToReport;
+ }
+
+ @Override
+ public void execute(AdminCommandContext context) {
+ display(AccessRequired.AccessCheck.relatedObjects(jobAccessChecks),context);
+ }
+
+ public static boolean skipJob(String name) {
+ return name == null || "attach".equals(name) || name.startsWith("_");
+ }
+
+
+ @Override
+ public Collection<? extends AccessRequired.AccessCheck> getAccessChecks() {
+ final List<JobInfo> jobInfoList = chooseJobs();
+ for (JobInfo jobInfo : jobInfoList) {
+ jobAccessChecks.add(new AccessRequired.AccessCheck<JobInfo>(jobInfo,
+ JobAuthorizationAttributeProcessor.JOB_RESOURCE_NAME_PREFIX + jobInfo.jobId,"read", false));
+ }
+ return jobAccessChecks;
+ }
+
+ public void display(Collection<JobInfo> jobInfoList, AdminCommandContext context) {
+ report = context.getActionReport();
+
+
+ int longestName = TITLE_NAME.length();
+ int longestJobId = TITLE_JOBID.length();
+ int longestTime = TITLE_TIME.length();
+ int longestState = TITLE_STATE.length();
+ int longestUser = TITLE_USER.length();
+ int longestExitCode = TITLE_EXITCODE.length();
+
+ for (JobInfo job :jobInfoList) {
+ int jobId = job.jobId.length();
+ int time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(job.commandExecutionDate).length();
+ int name = job.jobName.length();
+ int state = job.state.length();
+ int user ;
+ if(job.user != null){
+ user = job.user.length();
+ }else{
+ user = DEFAULT_USER_STRING.length();
+ }
+ int exitCode = job.exitCode.length();
+
+ if (name > longestName)
+ longestName = name;
+ if (time > longestTime)
+ longestTime = time;
+ if (jobId > longestJobId)
+ longestJobId = jobId;
+ if (state> longestState)
+ longestState = state;
+ if (user > longestUser)
+ longestUser = user;
+ if (exitCode> longestExitCode)
+ longestExitCode = exitCode;
+
+ }
+
+ if (jobInfoList.size() < 1) {
+ report.setMessage(TITLE_NONE);
+
+ }
+ longestName += 2;
+ longestJobId += 2;
+ longestState += 2;
+ longestTime += 2;
+ longestUser += 2;
+ longestExitCode +=2;
+
+
+ String formattedLine =
+ "%-" + longestName
+ + "s %-" + longestJobId
+ + "s %-" + longestTime
+ + "s %-" + longestState
+ + "s %-" + longestExitCode
+ + "s %-" + longestUser
+ + "s";
+
+
+ // no linefeed at the end!!!
+ boolean first = true;
+ MessagePart topMsg = report.getTopMessagePart();
+ Properties properties = report.getExtraProperties();
+ if (properties == null) {
+ properties = new Properties();
+ report.setExtraProperties(properties);
+ }
+ Collection<Map<String, Object>> details = new ArrayList<Map<String, Object>>();
+ properties.put("jobs", details);
+ for (JobInfo info : jobInfoList) {
+ if (first) {
+ topMsg.setMessage(String.format(formattedLine, TITLE_NAME, TITLE_JOBID, TITLE_TIME, TITLE_STATE,TITLE_EXITCODE,TITLE_USER ));
+ first = false;
+ }
+
+ MessagePart msg = topMsg.addChild();
+ msg.setMessage(String.format(formattedLine, info.jobName, info.jobId, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(info.commandExecutionDate), info.state,info.exitCode,info.user));
+ Map<String, Object> detail = new HashMap<String, Object>();
+ details.add(detail);
+ detail.put(NAME, info.jobName);
+ detail.put(ID, info.jobId);
+ detail.put(DATE, new Date(info.commandExecutionDate));
+ if (info.commandCompletionDate == 0)
+ //for a running job
+ detail.put(COMPLETION_DATE, " ");
+ else
+ // for a completed job
+ detail.put(COMPLETION_DATE, new Date(info.commandCompletionDate));
+ detail.put(STATE,info.state);
+ detail.put(CODE, info.exitCode);
+ detail.put(MESSAGE, info.message);
+ detail.put(USER, info.user);
+ }
+
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+
+}
+
+
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ListJvmOptions.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ListJvmOptions.java
new file mode 100644
index 0000000..f42e20c
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ListJvmOptions.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import com.sun.enterprise.util.i18n.StringManager;
+import java.util.List;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.*;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.internal.api.Target;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Lists the JVM options configured in server's configuration.
+ * @author केदार (km@dev.java.net)
+ * @author Kin-man Chung
+ * @since GlassFish V3
+ */
+@Service(name="list-jvm-options") //implements the cli command by this "name"
+@PerLookup //should be provided "per lookup of this class", not singleton
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("list.jvm.options")
+@ExecuteOn({RuntimeType.DAS})
+@TargetType({CommandTarget.DAS,CommandTarget.STANDALONE_INSTANCE,CommandTarget.CLUSTER,CommandTarget.CONFIG})
+@RestEndpoints({
+ @RestEndpoint(configBean=Domain.class,
+ opType=RestEndpoint.OpType.GET,
+ path="list-jvm-options",
+ description="list-jvm-options")
+})
+public final class ListJvmOptions implements AdminCommand, AdminCommandSecurity.Preauthorization {
+
+ @Param(name="target", optional=true, defaultValue = SystemPropertyConstants.DEFAULT_SERVER_INSTANCE_NAME)
+ String target;
+
+ @Param(name="profiler", optional=true)
+ Boolean profiler=false;
+
+ @Inject
+ Target targetService;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ private static final StringManager lsm = StringManager.getManager(ListJvmOptions.class);
+
+ @AccessRequired.To("read")
+ private JavaConfig jc;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ config = CLIUtil.updateConfigIfNeeded(config, targetService, target);
+ jc = config.getJavaConfig();
+ return true;
+ }
+
+ public void execute(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+ List<String> opts;
+ if (profiler) {
+ if (jc.getProfiler() == null) {
+ report.setMessage(lsm.getString("create.profiler.first"));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+ opts = jc.getProfiler().getJvmOptions();
+ } else
+ opts = jc.getJvmOptions();
+ //Collections.sort(opts); //sorting is garbled by Reporter anyway, so let's move sorting to the client side
+ try {
+ for (String option : opts) {
+ ActionReport.MessagePart part = report.getTopMessagePart().addChild();
+ part.setMessage(option);
+ }
+ } catch (Exception e) {
+ report.setMessage(lsm.getStringWithDefault("list.jvm.options.failed",
+ "Command: list-jvm-options failed"));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ return;
+ }
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ListThreadpools.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ListThreadpools.java
new file mode 100644
index 0000000..3582a80
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ListThreadpools.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+
+import java.util.List;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.ThreadPools;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.I18n;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandLock;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.config.support.CommandTarget;
+import org.glassfish.config.support.TargetType;
+import org.glassfish.internal.api.Target;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.hk2.api.ServiceLocator;
+
+import org.glassfish.grizzly.config.dom.ThreadPool;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import org.glassfish.api.admin.*;
+
+/**
+ * List Thread Pools command
+ */
+@Service(name = "list-threadpools")
+@PerLookup
+@CommandLock(CommandLock.LockType.NONE)
+@I18n("list.threadpools")
+@TargetType({CommandTarget.DAS, CommandTarget.STANDALONE_INSTANCE, CommandTarget.CLUSTER, CommandTarget.CONFIG,
+ CommandTarget.CLUSTERED_INSTANCE})
+@RestEndpoints({
+ @RestEndpoint(configBean=ThreadPools.class,
+ opType=RestEndpoint.OpType.GET,
+ path="list-threadpools",
+ description="list-threadpools")
+})
+public class ListThreadpools implements AdminCommand, AdminCommandSecurity.Preauthorization {
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ @Inject
+ Domain domain;
+
+ @Param(name = "target", primary = true, defaultValue = SystemPropertyConstants.DAS_SERVER_NAME)
+ String target;
+
+ @Inject
+ ServiceLocator habitat;
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ListThreadpools.class);
+
+ @AccessRequired.To("read")
+ private ThreadPools threadPools;
+
+ @Override
+ public boolean preAuthorization(AdminCommandContext context) {
+ config = CLIUtil.updateConfigIfNeeded(config, target, habitat);
+ threadPools = config.getThreadPools();
+ return true;
+ }
+
+ /**
+ * Executes the command
+ *
+ * @param context information
+ */
+ public void execute(AdminCommandContext context) {
+ final ActionReport report = context.getActionReport();
+ try {
+ List<ThreadPool> poolList = threadPools.getThreadPool();
+ for (ThreadPool pool : poolList) {
+ final ActionReport.MessagePart part = report.getTopMessagePart()
+ .addChild();
+ part.setMessage(pool.getName());
+ }
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ } catch (Exception e) {
+ String str = e.getMessage();
+ report.setMessage(localStrings.getLocalString("list.thread.pools" +
+ ".failed", "List Thread Pools failed because of: " + str));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ report.setFailureCause(e);
+ }
+ }
+}
+
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/LocalStrings.properties b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/LocalStrings.properties
new file mode 100644
index 0000000..3d27de1
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/LocalStrings.properties
@@ -0,0 +1,125 @@
+#
+# Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+
+create.jvm.options=creates JVM options in the Java configuration or profiler element of the domain.xml file.
+create.jvm.options.jvm_option_name=The left side of the equal sign (=) is the JVM option name. The right side of the equal sign (=) is the JVM option value. A colon (:) is a delimiter for multiple options.
+create.jvm.options.usagetext=create-jvm-options\n\t[--target <target(default:server)>]\n\t[--profiler[=<profiler(default:false)>]]\n\t[-?|--help[=<help(default:false)>]]\n\t(jvm_option_name[=jvm_option_value])[:jvm_option_name[=jvm_option_name]]*
+delete.jvm.options=removes JVM options from the Java configuration or profiler elements of the domain.xml file
+delete.jvm.options.jvm_option_name=The left side of the equal sign (=) is the JVM option name. The right side of the equal sign (=) is the JVM option value. A colon (:) is a delimiter for multiple options.
+delete.jvm.options.usagetext=delete-jvm-options\n\t[--target <target(default:server)>]\n\t[--profiler[=<profiler(default:false)>]]\n\t[-?|--help[=<help(default:false)>]]\n\t(jvm_option_name[=jvm_option_value])[:jvm_option_name[=jvm_option_name]]*
+list.jvm.options=lists JVM options in the Java configuration or profiler element of the domain.xml file.
+list.jvm.options.success=Listing configured JVM Options and Java System Properties on given target successful
+list.jvm.options.failed=Listing JVM options failed on given target for following reason: {0}
+create.jvm.options.success=Creating the given Option(s) on given target successful
+delete.jvm.options.success=Deleting the given Option(s) on given target successful
+delete.jvm.options.failed=Deleting given option(s) on given target failed for following reason,\nthe current options in configuration have been retained
+create.profiler.first=No profiler configured yet. Create a profiler first.
+created.message=Created {0} option(s)
+no.option.created=No jvm-options were created (perhaps they were already present)
+deleted.message=Deleted {0} option(s)
+no.option.deleted=No jvm-options were deleted (perhaps they never existed in the configuration)
+joe.exists=JVM option {0} already exists in the configuration.
+joe.invalid.start=JVM option {0} is invalid because it does not start with a ''-''
+joe.invalid.cmd.syntax=The command line:{0} does not satisfy the syntax.\nIn a nutshell, all options should start with a ''-'', multiple options are separated by a '':''.\nA '':'' inside an option should be escaped with a ''\\''.\nSince shell interprets command arguments, make sure you quote it.\n
+soft.invalid.xmx=It appears that given JVM option {0} represents invalid maximum heap for the JVM. Ensure that it is valid, by doing list-jvm-options.
+soft.xmx.exists=The configuration already has maximum heap size specified: {0}. Verify the java configuration by doing list-jvm-options.
+soft.xmx.smaller.than.xms=It appears that the maximum heap size specified: {0} is smaller than the minimum heap size in the configuration: {1}. JVM might not start. Ensure that this is valid, by doing doing list-jvm-options.
+soft.invalid.xms=It appears that given JVM option {0} represents invalid initial heap for the JVM. Ensure that it is valid, by doing list-jvm-options.
+soft.xms.exists=The configuration already has initial heap size specified: {0}. Verify the java configuration by doing list-jvm-options.
+soft.xms.larger.than.xmx=It appears that the initial heap size specified: {0} is larger than the maximum heap size in the configuration: {1}. JVM might not start. Ensure that this is valid, by doing doing list-jvm-options.
+#Generate JVM Report
+server.unreachable=The server {0} seems to be unreachable. This means either it is not running or there is an internal communication error.
+td.title=Full Java Thread Dump {0} {1} {2}
+thread.no=Number of threads: {0}
+daemon.thread.no=Number of daemon threads: {0}
+peak.thread.no=Peak live thread count since the Java virtual machine started or peak was reset: {0}
+thread.contention.monitoring.supported=Is support for thread contention monitoring available on this JVM? [{0}]
+thread.contention.monitoring.enabled=Is thread contention monitoring enabled? [{0}]. If false, some thread synchronization statistics are not be available.
+thread.cputime.supported=Is support for CPU time measurement for any thread available on this JVM? [{0}]
+thread.cputime.enabled=Is thread CPU time measurement enabled? [{0}]. If false, thread execution times are not available for any thread.
+execution.info=Thread Execution Information:
+thread.title=Thread {0} thread-id: {1} thread-state: {2}
+thread.waiting.on=Waiting on lock: {0}
+thread.suspended=Suspended
+thread.in.native=Running in native
+thread.stack.element=\t at: {0}
+no.deadlock=No deadlock found
+sync.info=Thread Synchronization Statistics:
+thread.blocked.times=Number of times this thread was blocked (to enter/reenter a Monitor): {0}
+thread.blocked.totaltime=Total (approximate) time the thread was in BLOCKED state: {0} milliseconds since thread contention monitoring was last enabled.
+thread.total.cpu.time=Total CPU time for this thread: {0} seconds {1} nanoseconds.
+thread.cpu.user.time=User-level CPU time for this thread: {0} seconds {1} nanoseconds.
+wait.times=Number of times this thread waited for a notification (i.e. it was in WAITING or TIMED_WAITING state): {0}
+lock.owner.details=This thread is blocked waiting on lock owned currently by thread named: {0}, id: {1}
+monitor.info=Object Monitors currently held or requested by this thread: {0}
+ownable.sync.info=Ownable Synchronizers (e.g. ReentrantLock and ReentrantReadWriteLock) held by this thread: {0}
+deadlocks.found=Following thread(s) were deadlocked:
+m2hms={0} Hours {1} Minutes {2} Seconds
+m2sms={0} Seconds {1} Milliseconds
+uptime=The uptime of Java Virtual Machine: {0}
+memory.pool.name=Memory Pool Name: {0}
+memory.usage.init=Memory that Java Virtual Machine initially requested to the Operating System: {0} Bytes
+memory.usage.comm=Memory that Java Virtual Machine is guaranteed to receive from the Operating System: {0} Bytes
+memory.usage.max=Maximum Memory that Java Virtual Machine may get from the Operating System: {0} Bytes. Note that this is not guaranteed.
+memory.usage.used=Memory that Java Virtual Machine uses at this time: {0} Bytes
+gc.name=Name of the Garbage Collector: {0}
+gc.numcol=Number of collections occurred using this garbage collector: {0} Bytes
+gc.coltime=Garbage Collection Time: {0}
+heap.mem.usage=Heap Memory Usage:
+nonheap.mem.usage=Non-heap Memory Usage:
+obj.fin.pending=Approximate number of objects for which finalization is pending: {0}
+classloading.info=Class loading and unloading in the Java Virtual Machine:
+classes.loaded=Number of classes currently loaded in the Java Virtual Machine: {0}
+classes.total=Number of classes loaded in the Java Virtual Machine since the startup: {0}
+classes.unloaded=Number of classes unloaded from the Java Virtual Machine: {0}
+complilation.info=Just-in-time (JIT) compilation information in the Java Virtual Machine:
+compilation.monitor.status=Java Virtual Machine compilation monitoring allowed: {0}
+jit.compilar.name=Name of the Just-in-time (JIT) compiler: {0}
+compilation.time=Total time spent in compilation: {0}
+os.info=Operating System Information:
+os.name=Name of the Operating System: {0}
+os.arch=Binary Architecture name of the Operating System: {0}, Version: {1}
+os.nproc=Number of processors available on the Operating System: {0}
+os.load=System load on the available processors for the last minute: {0}. (Sum of running and queued runnable entities per minute)
+rt.info=General Java Runtime Environment Information for the VM: {0}
+rt.bcp=JRE BootClassPath: {0}
+rt.cp=JRE ClassPath: {0}
+rt.libpath=JRE Native Library Path: {0}
+rt.nvv=JRE name: {0} Vendor: {1} Version: {2}
+rt.sysprops=List of System Properties for the Java Virtual Machine:
+summary.title=**** Java Virtual Machine [App Server Instance Name: {0}] Summary ****
+class.info.title=**** Class Statistics for Java Virtual Machine [App Server Instance Name: {0}] ****
+thread.dump.title=**** Thread Dump for Java Virtual Machine [App Server Instance Name: {0}] ****
+memory.info.title=**** Memory (Perm Gen, Eden Space etc.) Information for Java Virtual Machine [App Server Instance Name: {0}] ****
+#logging information
+logging.config.file=Effective logging properties file:[{0}]. If null, it indicates JRE standard file.
+reg.loggers=Number of loggers currently registered in the JVM: [{0}]. Details follow:
+logger.details.1=If the level is blank, it is inherited from parent logger
+logger.details.2=Parent logger is the nearest existing parent logger
+list.of.loggers=Logger Name | Logging Level | Parent Logger Name
+create.threadpool.duplicate=Thread Pool named {0} already exists.
+create.threadpool.failed=Creation of: {0} failed because of: {1}
+create.threadpool.deprecated.workqueues=Deprecated Syntax: --workqueues option is deprecated for create-threadpool command.
+list.thread.pools.failed=List Thread Pools failed because of: {0}
+delete.threadpool.notexists=Thread Pool named {0} does not exist.
+delete.threadpool.failed=Delete Thread Pool failed because of: {0}
+attach.wrong.commandinstance.id=Job with id {0} does not exist.
+attach.finished=Command {0} executed with status {1}.
+user.not.authorized = User {0} not authorized to attach to job {1}
+
+getPayload.wrong.commandinstance.id=Job with id {0} does not exist.
+getPayload.nopayload=Outbound payload does not exist.
+getPayload.unsupported=Payload type is not supported. Can not download data.
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/LogReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/LogReporter.java
new file mode 100644
index 0000000..95c06fc
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/LogReporter.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.util.i18n.StringManager;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.LogManager;
+import java.util.logging.LoggingMXBean;
+
+/** Provides the logging information of all the loggers registered in the VM.
+ *
+ * @author केदार (km@dev.java.net)
+ * @since GlassFish v3
+ */
+public class LogReporter {
+
+ private final StringManager sm = StringManager.getManager(LogReporter.class);
+ private final String ROOT_LOGGER = "root";
+ private final String ANON_LOGGER = "anonymous";
+
+ public String getLoggingReport() throws RuntimeException {
+ try {
+ StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ LoggingMXBean lb = LogManager.getLoggingMXBean();
+ List<String> loggers = lb.getLoggerNames();
+ Collections.sort(loggers);
+ String lf = System.getProperty("java.util.logging.config.file");
+ sb.append(sm.getString("logging.config.file", lf));
+ sb.append(sm.getString("reg.loggers", loggers.size()));
+ sb.append(sm.getString("logger.details.1"));
+ sb.append(sm.getString("logger.details.2"));
+ sb.append(sm.getString("list.of.loggers"));
+ sb.append("--------------------------------------------------");
+ for (String logger : loggers) {
+ String ln = (logger == null) ? ANON_LOGGER : logger;
+ String parent = lb.getParentLoggerName(logger);
+ if (parent == null || parent.length() == 0)
+ parent = ROOT_LOGGER;
+ sb.append(ln + "|" + lb.getLoggerLevel(logger) + "|" + parent);
+ }
+ return (sb.toString());
+ } catch(Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/MemoryReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/MemoryReporter.java
new file mode 100644
index 0000000..7eda44d
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/MemoryReporter.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.util.i18n.StringManager;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.management.RuntimeMXBean;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+/**
+ */
+class MemoryReporter {
+ private final MBeanServerConnection mbsc;
+ private RuntimeMXBean rmbean;
+ private MemoryMXBean mmbean;
+ private List<MemoryPoolMXBean> pools;
+ private List<GarbageCollectorMXBean> gcmbeans;
+ private final static StringManager sm = StringManager.getManager(MemoryReporter.class);
+
+ public MemoryReporter(final MBeanServerConnection mbsc) {
+ this.mbsc = mbsc;
+ }
+ public String getMemoryReport() {
+ init();
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ sb.append(getMemoryPoolReport());
+ sb.append(getGarbageCollectionReport());
+ sb.append(getMemoryMXBeanReport());
+ return ( sb.toString() );
+ }
+
+ private void init() throws RuntimeException {
+ try {
+ this.rmbean = ManagementFactory.newPlatformMXBeanProxy(mbsc,
+ ManagementFactory.RUNTIME_MXBEAN_NAME,
+ RuntimeMXBean.class);
+ this.mmbean = ManagementFactory.newPlatformMXBeanProxy(mbsc,
+ ManagementFactory.MEMORY_MXBEAN_NAME,
+ MemoryMXBean.class);
+ ObjectName poolName = new ObjectName(ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE+",*");;
+ ObjectName gcName = new ObjectName(ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE+",*");
+ Set mbeans = mbsc.queryNames(poolName, null);
+ if (mbeans != null) {
+ pools = new ArrayList<MemoryPoolMXBean>();
+ Iterator iterator = mbeans.iterator();
+ MemoryPoolMXBean p = null;
+ while (iterator.hasNext()) {
+ ObjectName objName = (ObjectName) iterator.next();
+ p = ManagementFactory.newPlatformMXBeanProxy(mbsc,
+ objName.getCanonicalName(),
+ MemoryPoolMXBean.class);
+ pools.add(p);
+ }
+ }
+ mbeans = mbsc.queryNames(gcName, null);
+ if (mbeans != null) {
+ gcmbeans = new ArrayList<GarbageCollectorMXBean>();
+ Iterator iterator = mbeans.iterator();
+ GarbageCollectorMXBean gc = null;
+ while (iterator.hasNext()) {
+ ObjectName objName = (ObjectName) iterator.next();
+ gc = ManagementFactory.newPlatformMXBeanProxy(mbsc,
+ objName.getCanonicalName(),
+ GarbageCollectorMXBean.class);
+ gcmbeans.add(gc);
+ }
+ }
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String getMemoryPoolReport() {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ final long millis = rmbean.getUptime();
+ final String uptime = sm.getString("uptime", JVMInformationCollector.millis2HoursMinutesSeconds(millis));
+ sb.append(uptime);
+ for (final MemoryPoolMXBean m : pools) {
+ final String n = m.getName();
+ sb.append(sm.getString("memory.pool.name", n));
+ MemoryUsage mu = m.getUsage();
+ sb.append(mu2String(mu));
+ }
+ return ( sb.toString() );
+ }
+ private String mu2String(final MemoryUsage mu) {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ final String init = JVMInformationCollector.formatLong(mu.getInit());
+ sb.append(sm.getString("memory.usage.init", init));
+ final String comm = JVMInformationCollector.formatLong(mu.getCommitted());
+ sb.append(sm.getString("memory.usage.comm", comm));
+ final String max = JVMInformationCollector.formatLong(mu.getMax());
+ sb.append(sm.getString("memory.usage.max", max));
+ final String used = JVMInformationCollector.formatLong(mu.getUsed());
+ sb.append(sm.getString("memory.usage.used", used));
+ return ( sb.toString() );
+ }
+ private String getGarbageCollectionReport() {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ for (final GarbageCollectorMXBean m : gcmbeans) {
+ final String name = sm.getString("gc.name", m.getName());
+ sb.append(name);
+ final String cc = sm.getString("gc.numcol", JVMInformationCollector.formatLong(m.getCollectionCount()));
+ sb.append(cc);
+ final String gct = sm.getString("gc.coltime", JVMInformationCollector.millis2SecondsMillis(m.getCollectionTime()));
+ sb.append(gct);
+ }
+ return ( sb.toString() );
+ }
+ private String getMemoryMXBeanReport() {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ sb.append(sm.getString("heap.mem.usage"));
+ sb.append(mu2String(mmbean.getHeapMemoryUsage()));
+ sb.append(sm.getString("nonheap.mem.usage"));
+ sb.append(mu2String(mmbean.getNonHeapMemoryUsage()));
+ sb.append(sm.getString("obj.fin.pending", mmbean.getObjectPendingFinalizationCount()));
+ return ( sb.toString() );
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/StringBuilderNewLineAppender.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/StringBuilderNewLineAppender.java
new file mode 100644
index 0000000..db3c8f7
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/StringBuilderNewLineAppender.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+import java.io.*;
+
+/**
+ */
+class StringBuilderNewLineAppender {
+
+ private StringBuilder sb;
+ static final String SEP = System.getProperty("line.separator");
+ /** Creates a new instance of StringBuilderNewLineAppender */
+ StringBuilderNewLineAppender(final StringBuilder sb) {
+ this.sb = sb;
+ }
+ StringBuilderNewLineAppender append(final String s) {
+ sb.append(s);
+ sb.append(SEP);
+ return ( this );
+ }
+ public String toString() {
+ return ( sb.toString() );
+ }
+ public String toString(String... filterOut) {
+ String sbString = sb.toString();
+ BufferedReader in = new BufferedReader(new StringReader(sbString));
+ sb = new StringBuilder();
+
+ try
+ {
+ readloop:
+ for(String s = in.readLine(); s != null; s = in.readLine()){
+ for(String filter : filterOut){
+ if(s.startsWith(filter))
+ continue readloop; // continue to outer loop
+ }
+ append(s);
+ }
+ }
+ catch(Exception e)
+ {
+ // bail
+ return sbString;
+ }
+
+ return toString();
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/SummaryReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/SummaryReporter.java
new file mode 100644
index 0000000..9612d49
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/SummaryReporter.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.util.StringUtils;
+import com.sun.enterprise.util.i18n.StringManager;
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.TreeMap;
+import javax.management.MBeanServerConnection;
+
+
+class SummaryReporter {
+
+ private final MBeanServerConnection mbsc;
+ private final StringManager sm = StringManager.getManager(SummaryReporter.class);
+ private final static String secretProperty = "module.core.status";
+
+ public SummaryReporter(final MBeanServerConnection mbsc) {
+ this.mbsc = mbsc;
+ }
+ public String getSummaryReport() throws RuntimeException {
+ try {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ final OperatingSystemMXBean os = ManagementFactory.newPlatformMXBeanProxy(mbsc,
+ ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class);
+ sb.append(getOSInfo(os));
+ final RuntimeMXBean rt = ManagementFactory.newPlatformMXBeanProxy(mbsc,
+ ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
+ sb.append(getVMInfo(rt));
+ return ( sb.toString(secretProperty) );
+ } catch(final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String getOSInfo(final OperatingSystemMXBean os) {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ sb.append(sm.getString("os.info"));
+ sb.append(sm.getString("os.name", os.getName()));
+ sb.append(sm.getString("os.arch", os.getArch(), os.getVersion()));
+ sb.append(sm.getString("os.nproc", os.getAvailableProcessors()));
+ sb.append(sm.getString("os.load", getSystemLoad(os)));
+ return ( sb.toString() );
+ }
+ private String getVMInfo(final RuntimeMXBean rt) {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ sb.append(sm.getString("rt.info", rt.getName()));
+ sb.append(sm.getString("rt.bcp", rt.getBootClassPath()));
+ sb.append(sm.getString("rt.cp", rt.getClassPath()));
+ sb.append(sm.getString("rt.libpath", rt.getLibraryPath()));
+ sb.append(sm.getString("rt.nvv", rt.getVmName(), rt.getVmVendor(), rt.getVmVersion()));
+ sb.append(getProperties(rt));
+ return ( sb.toString() );
+ }
+ private String getProperties(final RuntimeMXBean rt) {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ final Map<String, String> unsorted = rt.getSystemProperties();
+ // I decided to sort this for better readability -- 27 Feb 2006
+ final TreeMap<String, String> props = new TreeMap<String, String>(unsorted);
+ sb.append(sm.getString("rt.sysprops"));
+ for (Map.Entry<String, String> entry : props.entrySet()) {
+ sb.append(entry.getKey()).append(" = ").append(filterForbidden(entry.getKey(), entry.getValue()));
+ }
+ return ( sb.toString() );
+ }
+
+ private String getSystemLoad(OperatingSystemMXBean os) {
+ //available only on 1.6
+ String info = ThreadMonitor.NA;
+ try {
+ String METHOD = "getSystemLoadAverage";
+ Method m = os.getClass().getMethod(METHOD, (Class[]) null);
+ if (m != null) {
+ Object ret = m.invoke(os, (Object[])null);
+ return ( ret.toString() );
+ }
+ } catch(Exception e) {
+
+ }
+ return ( info );
+ }
+
+ private String filterForbidden(String key, String value) {
+ if(StringUtils.ok(key) && key.startsWith("javax.net.ssl.") && key.indexOf("password") >= 0)
+ return "********";
+ else
+ return value;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ThreadMonitor.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ThreadMonitor.java
new file mode 100644
index 0000000..d0e8ac7
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/ThreadMonitor.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * ThreadMonitor.java
+ *
+ * Created on July 21, 2005, 11:50 AM
+ */
+
+package com.sun.enterprise.v3.admin.commands;
+
+import com.sun.enterprise.util.i18n.StringManager;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.util.Arrays;
+import javax.management.MBeanServerConnection;
+
+/**
+ */
+class ThreadMonitor {
+
+ private final MBeanServerConnection mbsc;
+ private final StringManager sm = StringManager.getManager(ThreadMonitor.class);
+ private static final BigInteger S2NANOS = new BigInteger("" + 1000000000);
+ public ThreadMonitor(final MBeanServerConnection mbsc) {
+ this.mbsc = mbsc;
+ }
+ public final String getThreadDump() {
+ //final long start = System.currentTimeMillis();
+ final StringBuilder sb = new StringBuilder();
+ final StringBuilderNewLineAppender td = new StringBuilderNewLineAppender(sb);
+ try {
+ final ThreadMXBean tmx = ManagementFactory.newPlatformMXBeanProxy(mbsc, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
+ final String title = getTitle();
+ td.append(title);
+ td.append(sm.getString("thread.no", tmx.getThreadCount()));
+ td.append(sm.getString("daemon.thread.no", tmx.getDaemonThreadCount()));
+ td.append(sm.getString("peak.thread.no", tmx.getPeakThreadCount()));
+ boolean tc = (tmx.isThreadContentionMonitoringSupported()) ? true : false;
+ td.append(sm.getString("thread.contention.monitoring.supported", tc));
+ boolean tce = (tmx.isThreadContentionMonitoringEnabled()) ? true : false;
+ td.append(sm.getString("thread.contention.monitoring.enabled", tce));
+ boolean cputs = (tmx.isThreadCpuTimeSupported()) ? true : false;
+ td.append(sm.getString("thread.cputime.supported", cputs));
+ boolean cpute = (tmx.isThreadCpuTimeEnabled()) ? true : false;
+ td.append(sm.getString("thread.cputime.enabled", cpute));
+ final long[] tids = tmx.getAllThreadIds();
+ final ThreadInfo[] tinfos = tmx.getThreadInfo(tids, Integer.MAX_VALUE);
+ /*
+ Arrays.sort(tinfos, new Comparator<ThreadInfo> () {
+ public int compare(ThreadInfo a, ThreadInfo b) {
+ return ( a.getThreadName().compareTo(b.getThreadName()) );
+ }
+ });
+ */
+ for (final ThreadInfo ti : tinfos) {
+ td.append(dumpThread(tmx, ti));
+ }
+ sb.append(getDeadlockInfo(tmx));
+ return ( td.toString() );
+ } catch(final Exception e) {
+ throw new RuntimeException(e);
+ }
+ /*finally {
+ final long end = System.currentTimeMillis();
+ final double time = (end/1000.0) - (start/1000.0);
+ //logger.info("Time in seconds to get the jvm thread dump: " + time);
+ }*/
+ }
+ private String dumpThread(ThreadMXBean tmx, ThreadInfo ti) {
+ String msg = "--------------------------------------------------------------------------------";
+ final StringBuilder sb = new StringBuilder(msg).append(StringBuilderNewLineAppender.SEP);
+ sb.append(sm.getString("execution.info")).append(StringBuilderNewLineAppender.SEP);
+ sb.append("-----------------------").append(StringBuilderNewLineAppender.SEP);
+ final long ids = ti.getThreadId();
+ final String ss = ti.getThreadState().toString();
+ msg = sm.getString("thread.title", quote(ti.getThreadName()), ids, ss);
+ sb.append(msg);
+ if (ti.getLockName() != null) {
+ msg = sm.getString("thread.waiting.on", ti.getLockName());
+ sb.append(" " + msg);
+ }
+ if (ti.isSuspended()) {
+ msg = sm.getString("thread.suspended");
+ sb.append(" " + msg);
+ }
+ if (ti.isInNative()) {
+ msg = sm.getString("thread.in.native");
+ sb.append(" " + msg);
+ }
+ sb.append(StringBuilderNewLineAppender.SEP);
+ for (final StackTraceElement ste : ti.getStackTrace()) {
+ msg = sm.getString("thread.stack.element", ste.toString());
+ sb.append(msg);
+ sb.append(StringBuilderNewLineAppender.SEP);
+ }
+ msg = sm.getString("sync.info");
+ sb.append(msg).append(StringBuilderNewLineAppender.SEP);
+ sb.append("-----------------------").append(StringBuilderNewLineAppender.SEP);
+ if (ti.getLockOwnerName() != null) {
+ msg = sm.getString("lock.owner.details", ti.getLockOwnerName(), ti.getLockOwnerId());
+ sb.append(msg).append(StringBuilderNewLineAppender.SEP);
+ }
+ msg = sm.getString("thread.blocked.times", ti.getBlockedCount());
+ sb.append(msg).append(StringBuilderNewLineAppender.SEP);
+ long bt = ti.getBlockedTime();
+ if (bt != -1) { //if bt == -1 thread contention monitoring is not enabled, reported above
+ msg = sm.getString("thread.blocked.totaltime", bt);
+ sb.append(msg).append(StringBuilderNewLineAppender.SEP);
+ }
+ long wt = ti.getWaitedCount();
+ msg = sm.getString("wait.times", wt);
+ sb.append(msg).append(StringBuilderNewLineAppender.SEP);
+ boolean tcput = tmx.isThreadCpuTimeEnabled() ? true : false;
+ if (tcput) {
+ long cput = tmx.getThreadCpuTime(ti.getThreadId());
+ if (cput != -1) {
+ BigInteger[] times = new BigInteger(cput + "").divideAndRemainder(S2NANOS);
+ msg = sm.getString("thread.total.cpu.time", times[0], times[1]);
+ sb.append(msg).append(StringBuilderNewLineAppender.SEP);
+ }
+ long user = tmx.getThreadUserTime(ti.getThreadId());
+ if (user != -1) {
+ BigInteger[] times = new BigInteger(cput + "").divideAndRemainder(S2NANOS);
+ msg = sm.getString("thread.cpu.user.time", times[0], times[1]);
+ sb.append(msg).append(StringBuilderNewLineAppender.SEP);
+ }
+ }
+ msg = sm.getString("lock.owner.details", ti.getLockOwnerName(), ti.getLockOwnerId());
+ msg = getMoreThreadInfo(ti, "getLockedMonitors");
+ sb.append(sm.getString("monitor.info", msg)).append(StringBuilderNewLineAppender.SEP);
+ msg = getMoreThreadInfo(ti, "getLockedSynchronizers");
+ sb.append(sm.getString("ownable.sync.info", msg));
+ return ( sb.toString() );
+ }
+
+ private String getTitle() throws Exception {
+ final RuntimeMXBean rt = ManagementFactory.newPlatformMXBeanProxy(mbsc, ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
+ final String vmname = rt.getVmName();
+ final String vmversion = rt.getVmVersion();
+ final String vmvendor = rt.getVmVendor();
+ final String title = sm.getString("td.title", vmname, vmversion, vmvendor);
+
+ return ( title );
+ }
+
+ private String quote(final String uq) {
+ final StringBuilder sb = new StringBuilder("\"");
+ sb.append(uq).append("\"");
+ return ( sb.toString() );
+ }
+
+ private String getDeadlockInfo(final ThreadMXBean tmx) {
+ final StringBuilderNewLineAppender sb = new StringBuilderNewLineAppender(new StringBuilder());
+ final long[] dts = tmx.findMonitorDeadlockedThreads();
+ if (dts == null) {
+ sb.append(sm.getString("no.deadlock"));
+ }
+ else {
+ sb.append(sm.getString("deadlocks.found"));
+ for (final long dt : dts) {
+ final ThreadInfo ti = tmx.getThreadInfo(dt);
+ sb.append(this.dumpThread(tmx, ti));
+ }
+ }
+ return ( sb.toString() );
+ }
+
+ private String getMoreThreadInfo(ThreadInfo ti, String mn) {
+ String ms = "";
+ try {
+ Method glmm = ti.getClass().getDeclaredMethod(mn, (Class[])null);
+ Object monitors = glmm.invoke(ti, (Object[])null);
+ if (monitors instanceof Object[]) {
+ return ( Arrays.toString((Object[])monitors) );
+ } else {
+ return (NA);
+ }
+ } catch(Exception e) {
+ return (NA);
+ }
+ }
+
+ public static final String NA = "NOT_AVAILABLE";
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/package-info.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/package-info.java
new file mode 100644
index 0000000..6408961
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/commands/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/**
+ * All the general utility admin commands may be placed in this package.
+ * Since the server is modular now, the commands are likely to reside with
+ * modules, but the there are some commands that are of generic nature and
+ * this is the place for them.
+ * @author केदार (km@dev.java.net)
+ * @since GlassFish V3
+ */
+
+package com.sun.enterprise.v3.admin.commands;
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/instance/.gitkeep_empty_dir b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/instance/.gitkeep_empty_dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/instance/.gitkeep_empty_dir
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/listener/CombinedJavaConfigSystemPropertyListener.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/listener/CombinedJavaConfigSystemPropertyListener.java
new file mode 100644
index 0000000..3661753
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/listener/CombinedJavaConfigSystemPropertyListener.java
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin.listener;
+
+import com.sun.enterprise.config.serverbeans.Cluster;
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import com.sun.enterprise.config.serverbeans.Profiler;
+import com.sun.enterprise.config.serverbeans.Server;
+import com.sun.enterprise.config.serverbeans.SystemProperty;
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.config.support.TranslatedConfigView;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.Changed;
+import org.jvnet.hk2.config.Changed.TYPE;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.ConfigListener;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.ConfigView;
+import org.jvnet.hk2.config.NotProcessed;
+import org.jvnet.hk2.config.ObservableBean;
+import org.jvnet.hk2.config.Transactions;
+import org.jvnet.hk2.config.UnprocessedChangeEvents;
+import org.jvnet.hk2.config.types.Property;
+
+/**
+ * Listens for the changes to the configuration of JVM and Java system
+ * properties (including the Java VM options). Most of the effort involves the jvm-options
+ * list, but restart is also required for any changes to the java-config.
+ * <p>
+ * This class is implemented so that the server restart is NOT required if a deployer wants to deploy
+ * an application and the application depends on a particular Java system property
+ * (-D) to be specified. As of now, the deployer specifies the system property
+ * and deploys the application and the application should find it when it does
+ * System.getProperty("property-name"). Here is the complete algorithm:
+ *
+ * <ol>
+ * <li> If any of the attributes of the java-config element (JavaConfig) change,
+ * this listener flags it as server-restart-required kind of change.
+ * </li>
+ * <li> If a system property is being defined and it is NOT one that starts with
+ * "-Djava." or "-Djavax.", it will be immediately set in the System using
+ * System.setProperty() call. A server restart won't be needed.
+ * </li>
+ * <li> If any other JVM option is defined that does not start with "-D" (excluding
+ * the cases covered above), it is deemed to be a JVM option resulting
+ * in server-restart-required flag set.
+ * </li>
+ * <li> If a System Property (with above distinctions) is removed, System.clearProperty()
+ * is called and server-restart-required flag is set accordingly.
+ * </li>
+ * </ol>
+ * Change in the value of a particular system property level is not handled explicitly.
+ * User interfaces should take a note of it. e.g. CLI does not make -Dfoo=bar and -Dfoo=bar1
+ * as same properties being set to two different values since it is hard to distinguish it
+ * in general case. Users should delete -Dfoo=bar and add -Dfoo=bar1explicitly in this case.
+ * @author केदार (km@dev.java.net)
+ * @since GlassFish V3
+ * @see com.sun.enterprise.config.serverbeans.JavaConfig
+ */
+
+@Service
+@RunLevel(mode = RunLevel.RUNLEVEL_MODE_VALIDATING, value = 1) //from 1
+public final class CombinedJavaConfigSystemPropertyListener implements PostConstruct, ConfigListener {
+ @Inject
+ ServiceLocator habitat;
+
+ @Inject
+ Transactions transactions;
+
+ /* The following objects are not injected so that this
+ * ConfigListener doesn't become a listener for those objects.
+ */
+ private Domain domain; //note: this should be current, and does contain the already modified values!
+ private Cluster cluster;
+ private Config config; // this is the server's Config
+ private Server server;
+
+ // The JavaConfig cannot be injected because it might not be the right
+ // one that gets injected. The JavaConfig is obtained from the Config
+ // in postConstruct below.
+ private JavaConfig jc;
+
+
+ volatile List<String> oldProps;
+ /* Implementation note: See 6028*/
+
+ volatile Map<String,String> oldAttrs;
+
+ static final Logger logger = KernelLoggerInfo.getLogger();
+
+ @Override
+ public void postConstruct() {
+ domain = habitat.getService(Domain.class);
+ cluster = habitat.getService(Cluster.class, ServerEnvironment.DEFAULT_INSTANCE_NAME);
+ config = habitat.getService(Config.class, ServerEnvironment.DEFAULT_INSTANCE_NAME);
+ server = habitat.getService(Server.class, ServerEnvironment.DEFAULT_INSTANCE_NAME);
+ jc = config.getJavaConfig();
+ if (jc != null) {
+ // register to listen for config events on the JavaConfig
+ ((ObservableBean)ConfigSupport.getImpl(jc)).addListener(this);
+ }
+ if (jc != null && jc.getJvmOptions() != null) {
+ oldProps = new ArrayList<String>(jc.getJvmOptions()); //defensive copy
+ oldAttrs = collectAttrs(jc);
+ }
+ transactions.addListenerForType(SystemProperty.class, this);
+ }
+
+ /**
+ Get attributes as a Map so that we can do an easy compare of old vs new and
+ also emit a useful change message.
+ <p>
+ This list must contain all attributes that are relevant to restart-required.
+ */
+ private static Map<String,String> collectAttrs(final JavaConfig jc)
+ {
+ final Map<String,String> values = new HashMap<String,String>();
+ values.put( "JavaHome", jc.getJavaHome() );
+ values.put( "DebugEnabled", jc.getDebugEnabled() );
+ values.put( "DebugOptions", jc.getDebugOptions() );
+ values.put( "RmicOptions", jc.getRmicOptions() );
+ values.put( "JavacOptions", jc.getJavacOptions() );
+ values.put( "ClasspathPrefix", jc.getClasspathPrefix() );
+ values.put( "ClasspathSuffix", jc.getClasspathSuffix() );
+ values.put( "ServerClasspath", jc.getServerClasspath() );
+ values.put( "SystemClasspath", jc.getSystemClasspath() );
+ values.put( "NativeLibraryPathPrefix", jc.getNativeLibraryPathPrefix() );
+ values.put( "NativeLibraryPathSuffix", jc.getNativeLibraryPathSuffix() );
+ values.put( "BytecodePreprocessors", jc.getBytecodePreprocessors() );
+ values.put( "EnvClasspathIgnored", jc.getEnvClasspathIgnored() );
+
+ return values;
+ }
+
+ /* force serial behavior; don't allow more than one thread to make a mess here */
+ @Override
+ public synchronized UnprocessedChangeEvents changed(PropertyChangeEvent[] events) {
+ // ignore a REMOVE and an ADD of the same value
+
+ final UnprocessedChangeEvents unp = ConfigSupport.sortAndDispatch(events, new Changed() {
+ @Override
+ public <T extends ConfigBeanProxy> NotProcessed changed(TYPE type, Class<T> tc, T t) {
+ NotProcessed result = null;
+
+ if (tc == Profiler.class) {
+ result = new NotProcessed("Creation or changes to a profiler require restart");
+ }
+ else if (tc == Property.class && t.getParent().getClass() == JavaConfig.class) {
+ result = new NotProcessed("Addition of properties to JavaConfig requires restart");
+ }
+ else if (tc == JavaConfig.class && t instanceof JavaConfig) {
+ final JavaConfig njc = (JavaConfig) t;
+ logFine(type, njc);
+
+ // we must *always* check the jvm options, no way to know except by comparing,
+ // plus we should send an appropriate message back for each removed/added item
+ final List<String> curProps = new ArrayList<String>( njc.getJvmOptions() );
+ final boolean jvmOptionsWereChanged = ! oldProps.equals(curProps);
+ final List<String> reasons = handle(oldProps, curProps);
+ oldProps = curProps;
+
+ // something in the JavaConfig itself changed
+ // to do this well, we ought to keep a list of attributes, so we can make a good message
+ // saying exactly which attribute what changed
+ final Map<String,String> curAttrs = collectAttrs(njc);
+ reasons.addAll( handleAttrs( oldAttrs, curAttrs ) );
+ oldAttrs = curAttrs;
+
+ result = reasons.isEmpty() ? null : new NotProcessed( CombinedJavaConfigSystemPropertyListener.toString(reasons) );
+ }
+ else if (tc == SystemProperty.class && t instanceof SystemProperty) {
+ final SystemProperty sp = (SystemProperty) t;
+ // check to see if this system property is for this instance
+ ConfigBeanProxy proxy = sp.getParent();
+ ConfigView p = ConfigSupport.getImpl(proxy);
+
+
+ if (p == ConfigSupport.getImpl(server) ||
+ p == ConfigSupport.getImpl(config) ||
+ (cluster != null && p == ConfigSupport.getImpl(cluster)) ||
+ p == ConfigSupport.getImpl(domain)) {
+ // check to see if this system property is referenced by any of the options
+ String pname = sp.getName();
+ if (referencesProperty(pname, oldProps) ||
+ referencesProperty(pname, oldAttrs.values())) {
+ result = new NotProcessed("The system-property, " + pname + ", that is referenced by the Java configuration, was modified");
+ }
+ }
+ if (type == TYPE.ADD || type == TYPE.CHANGE) { //create-system-properties
+ if (proxy instanceof Domain) {
+ return addToDomain(sp);
+ } else if (proxy instanceof Config && p == ConfigSupport.getImpl(config)) {
+ return addToConfig(sp);
+ } else if (cluster != null && proxy instanceof Cluster && p == ConfigSupport.getImpl(cluster)) {
+ return addToCluster(sp);
+ } else if (proxy instanceof Server && p == ConfigSupport.getImpl(server)) {
+ return addToServer(sp);
+ }
+ } else if (type == TYPE.REMOVE) {
+ if (proxy instanceof Domain) {
+ return removeFromDomain(sp);
+ } else if (proxy instanceof Config && p == ConfigSupport.getImpl(config)) {
+ return removeFromConfig(sp);
+ } else if (cluster != null && proxy instanceof Cluster && p == ConfigSupport.getImpl(cluster)) {
+ return removeFromCluster(sp);
+ } else if (proxy instanceof Server && p == ConfigSupport.getImpl(server)) {
+ return removeFromServer(sp);
+ }
+ }
+ }
+ else {
+ // ignore other changes that are reported
+ }
+
+ return result;
+ }
+ }
+ , logger);
+ return unp;
+ }
+
+ private void logFine(TYPE ct, JavaConfig njc) {
+ final Level level = Level.FINE;
+ if (logger.isLoggable(level)) {
+ logger.log(level, "<java-config> changed");
+ int os = oldProps.size(), ns = njc.getJvmOptions().size();
+ if (os > ns) {
+ logger.log(level, "a system property or a JVM option was removed (old size = {0}), new size: ({1}), restart is required, based on the property", new Object[]{os, ns});
+ } else if(os < ns) {
+ logger.log(level, "a system property or a JVM option was added, (old size = {0}), new size: ({1}), restart is required, based on the property", new Object[]{os, ns});
+ } else {
+ logger.log(level, "an attribute was changed, restart required");
+ }
+ }
+ }
+
+ private List<String>
+ handleAttrs( final Map<String,String> old, final Map<String,String> cur) {
+ if ( old.size() != cur.size() ) {
+ throw new IllegalArgumentException();
+ }
+
+ // find all the differences and generate helpful messages
+ final List<String> reasons = new ArrayList<String>();
+ for(final Map.Entry<String,String> olde : old.entrySet() ) {
+ final String key = olde.getKey();
+ final String oldValue = olde.getValue();
+ final String curValue = cur.get(key);
+
+ final boolean changed = (oldValue == null && curValue != null) ||
+ (oldValue != null && curValue == null) ||
+ (oldValue != null && ! oldValue.equals(curValue));
+ if ( changed ) {
+ reasons.add("JavaConfig attribute '" + key + "' was changed from '" + oldValue + "' to '" + curValue + "'");
+ }
+ }
+ return reasons;
+ }
+
+
+
+ private List<String> handle(List<String> old, List<String> cur) {
+ NotProcessed np = null;
+
+ final Set<String> added = new HashSet<String>(cur);
+ added.removeAll(old);
+
+ final Set<String> removed = new HashSet<String>(old);
+ removed.removeAll(cur);
+
+ return getNotProcessed(removed, added);
+ }
+ //using C-style ;)
+ private static final String SYS_PROP_REGEX = "=";
+
+ //TODO need to handle system property substitution here
+ private String[] nvp(final String s) {
+ final String[] nv = s.split(SYS_PROP_REGEX);
+ final String name = nv[0];
+ String value = s.substring(name.length());
+ if ( value.startsWith("=") ) {
+ value = value.substring(1);
+ }
+ value = TranslatedConfigView.getTranslatedValue(value).toString();
+ return new String[] { name, value };
+ }
+
+ static final String DPREFIX = "-D";
+
+ private static String stripPrefix(final String s)
+ {
+ return s.startsWith(DPREFIX) ? s.substring(DPREFIX.length()) : s;
+ }
+
+ private List<String> getNotProcessed(
+ final Set<String> removals,
+ final Set<String> additions)
+ {
+ //look at the list, clear and/or add system properties
+ // otherwise they require server restart
+
+ final List<String> reasons = new ArrayList<String>();
+ for( final String removed : removals) {
+ final String[] nv = nvp(removed);
+ final String name = nv[0];
+
+ if (possiblyDynamicallyReconfigurable(removed)) {
+ System.clearProperty(stripPrefix(name));
+ }
+ else {
+ // detect a removal/addition which is really a change
+ String newItem = null;
+ for( final String added : additions ) {
+ if ( name.equals( nvp(added)[0] ) ) {
+ newItem = added;
+ additions.remove(added);
+ break;
+ }
+ }
+ String msg = null;
+ if ( newItem != null ) {
+ msg = "Change from '" + removed + "' to '" + newItem + "' cannot take effect without server restart";
+ }
+ else {
+ msg = "Removal of: " + removed + " cannot take effect without server restart";
+ }
+ reasons.add(msg);
+ }
+ }
+
+ // process any remaining additions
+ for( final String added : additions) {
+ final String[] nv = nvp(added);
+ final String name = nv[0];
+ final String newValue = nv[1];
+
+ if (possiblyDynamicallyReconfigurable(added)) {
+ System.setProperty( stripPrefix(name), newValue );
+ }
+ else {
+ reasons.add( "Addition of: '" + added + "' cannot take effect without server restart" );
+ }
+ }
+
+ return reasons;
+ }
+
+ private static String toString( final List<String> items ) {
+ final StringBuffer buf = new StringBuffer();
+ final String delim = ", ";
+ for( final String s : items ) {
+ if ( buf.length() != 0 ) {
+ buf.append(delim);
+ }
+ buf.append(s);
+ }
+
+ return buf.toString();
+ }
+
+
+ /** Determines with some confidence level if a particular String denotes
+ * a system property that can be set in the current JVM's (i.e. the JVM where
+ * this method's code runs) System. Anything that does not start with
+ * "-D" is not dynamically settable. However, anything that starts with "-Djava."
+ * or "-Djavax." is not dynamically settable.
+ */
+ private boolean possiblyDynamicallyReconfigurable(String s) {
+ if (s.startsWith(DPREFIX) && !s.startsWith("-Djava.")
+ && !s.startsWith("-Djavax."))
+ return true;
+ return false;
+ }
+
+ /*
+ * Deterines whether the given property name, pname, is references by any
+ * of the values in the values list. A reference is of the form ${pname}.
+ * Returns true if the pname is referenced.
+ */
+ static private boolean referencesProperty(String pname, Collection<String> values) {
+ String ref = "${" + pname + "}";
+ for (String v : values) {
+ if ((v != null) && (v.contains(ref)))
+ return true;
+ }
+ return false;
+ }
+ /*
+ * Notification events can come out of order, i.e., a create-system-properties
+ * on an existing property sends an ADD or the new one, a CHANGE, followed by
+ * a REMOVE of the old one. So we need to check if the property is still
+ * there.
+ */
+ private NotProcessed removeFromServer(SystemProperty sp) {
+ SystemProperty sysProp = getServerSystemProperty(sp.getName());
+ if (sysProp == null)
+ sysProp = getClusterSystemProperty(sp.getName());
+ if (sysProp == null)
+ sysProp = getConfigSystemProperty(sp.getName());
+ if (sysProp == null)
+ sysProp = getDomainSystemProperty(sp.getName());
+ if (sysProp == null) {
+ System.clearProperty(sp.getName());
+ } else {
+ System.setProperty(sysProp.getName(), sysProp.getValue());
+ }
+ return null; //processed
+ }
+
+ private NotProcessed removeFromCluster(SystemProperty sp) {
+ SystemProperty sysProp = getConfigSystemProperty(sp.getName());
+ if (sysProp == null)
+ sysProp = getDomainSystemProperty(sp.getName());
+ if (sysProp == null) {
+ if (!serverHas(sp))
+ System.clearProperty(sp.getName()); //if server overrides it anyway, this should be a noop
+ } else {
+ if (!serverHas(sp))
+ System.setProperty(sysProp.getName(), sysProp.getValue());
+ }
+ return null; //processed
+ }
+
+ private NotProcessed removeFromConfig(SystemProperty sp) {
+ SystemProperty sysProp = getDomainSystemProperty(sp.getName());
+ if (sysProp == null) {
+ if (!serverHas(sp) && !clusterHas(sp))
+ System.clearProperty(sp.getName()); //if server overrides it anyway, this should be a noop
+ } else {
+ if (!serverHas(sp) && !clusterHas(sp))
+ System.setProperty(sysProp.getName(), sysProp.getValue());
+ }
+ return null; //processed
+ }
+
+ private NotProcessed removeFromDomain(SystemProperty sp) {
+ if(!serverHas(sp)&& !clusterHas(sp) && !configHas(sp))
+ System.clearProperty(sp.getName()); //if server, cluster, or config overrides it anyway, this should be a noop
+ return null; //processed
+ }
+
+ private NotProcessed addToServer(SystemProperty sp) {
+ System.setProperty(sp.getName(), sp.getValue());
+ return null; //processed
+ }
+
+ private NotProcessed addToCluster(SystemProperty sp) {
+ if (!serverHas(sp))
+ System.setProperty(sp.getName(), sp.getValue()); //if server overrides it anyway, this should be a noop
+ return null; //processed
+ }
+
+ private NotProcessed addToConfig(SystemProperty sp) {
+ if (!serverHas(sp) && !clusterHas(sp))
+ System.setProperty(sp.getName(), sp.getValue()); //if server or cluster overrides it anyway, this should be a noop
+ return null; //processed
+ }
+
+ private NotProcessed addToDomain(SystemProperty sp) {
+ if (!serverHas(sp) && !clusterHas(sp) && !configHas(sp))
+ System.setProperty(sp.getName(), sp.getValue()); //if server, cluster, or config overrides it anyway, this should be a noop
+ return null; //processed
+ }
+
+ private boolean serverHas(SystemProperty sp) {
+ List<SystemProperty> ssps = server.getSystemProperty();
+ return hasSystemProperty(ssps, sp);
+ }
+
+ private boolean configHas(SystemProperty sp) {
+ Config c = domain.getConfigNamed(server.getConfigRef());
+ return c != null ? hasSystemProperty(c.getSystemProperty(), sp) : false;
+ }
+
+ private boolean clusterHas(SystemProperty sp) {
+ Cluster c = domain.getClusterForInstance(server.getName());
+ return c != null ? hasSystemProperty(c.getSystemProperty(), sp) : false;
+ }
+
+ private SystemProperty getServerSystemProperty(String spName) {
+ return getSystemProperty(server.getSystemProperty(), spName);
+ }
+
+ private SystemProperty getClusterSystemProperty(String spName) {
+ Cluster c = domain.getClusterForInstance(server.getName());
+ return c != null ? getSystemProperty(c.getSystemProperty(), spName) : null;
+ }
+
+ private SystemProperty getConfigSystemProperty(String spName) {
+ Config c = domain.getConfigNamed(server.getConfigRef());
+ return c != null ? getSystemProperty(c.getSystemProperty(), spName) : null;
+ }
+
+ private SystemProperty getDomainSystemProperty(String spName) {
+ return getSystemProperty(domain.getSystemProperty(), spName);
+ }
+
+ private boolean hasSystemProperty(List<SystemProperty> ssps, SystemProperty sp) {
+ return getSystemProperty(ssps, sp.getName()) != null;
+ }
+
+ /*
+ * Return the SystemProperty from the list of system properties with the
+ * given name. If the property is not there, or the list is null, return
+ * null.
+ */
+ private SystemProperty getSystemProperty(List<SystemProperty> ssps, String spName) {
+ if (ssps != null) {
+ for (SystemProperty sp : ssps) {
+ if (sp.getName().equals(spName)) {
+ return sp;
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/listener/package-info.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/listener/package-info.java
new file mode 100644
index 0000000..6cae640
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/listener/package-info.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/** Contains configuration change listeners that listen for specific config
+ * events. With a config listener, there are two things that need to happen:
+ * <ul>
+ * <li> Implementation of the config listener for a particular @Configured interface</li>
+ * <li> Registration of the config listener implementation with the @Configured interface </li>
+ * </ul>
+ * Classes in this package should do the former, only.
+ * @author केदार (km@dev.java.net)
+ * @since GlassFish V3
+ * @see com.sun.enterprise.config.serverbeans
+ */
+
+package com.sun.enterprise.v3.admin.listener;
+
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/progress/.gitkeep_empty_dir b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/progress/.gitkeep_empty_dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/admin/progress/.gitkeep_empty_dir
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/bootstrap/DerbyLifecycle.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/bootstrap/DerbyLifecycle.java
new file mode 100644
index 0000000..ec8c658
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/bootstrap/DerbyLifecycle.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * DerbyLifecycle.java
+ *
+ * Created on November 3, 2006, 2:03 PM
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package com.sun.enterprise.v3.bootstrap;
+
+import com.sun.enterprise.module.LifecyclePolicy;
+import com.sun.enterprise.module.Module;
+import com.sun.enterprise.module.ModuleState;
+import com.sun.enterprise.module.common_impl.LogHelper;
+import java.util.logging.Level;
+
+/**
+ *
+ * @author dochez
+ */
+public class DerbyLifecycle implements LifecyclePolicy {
+
+ /** Creates a new instance of DerbyLifecycle */
+ public DerbyLifecycle() {
+ }
+
+ /**
+ * Callback when the module enters the {@link ModuleState#READY READY} state.
+ * This is a good time to do any type of one time initialization
+ * or set up access to resources
+ * @param module the module instance
+ */
+ public void start(Module module) {
+
+ try {
+ final Module myModule = module;
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ try {
+ Class driverClass = myModule.getClassLoader().loadClass("org.apache.derby.jdbc.EmbeddedDriver");
+ myModule.setSticky(true);
+ driverClass.newInstance();
+ } catch(ClassNotFoundException e) {
+ LogHelper.getDefaultLogger().log(Level.SEVERE, "Cannot load Derby Driver ",e);
+ } catch(java.lang.InstantiationException e) {
+ LogHelper.getDefaultLogger().log(Level.SEVERE, "Cannot instantiate Derby Driver", e);
+ } catch(IllegalAccessException e) {
+ LogHelper.getDefaultLogger().log(Level.SEVERE, "Cannot instantiate Derby Driver", e);
+ }
+ }
+ catch (RuntimeException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ thread.start();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+
+ }
+
+ /**
+ * Callback before the module starts being unloaded. The runtime will
+ * free all the module resources and returned to a {@link ModuleState#NEW NEW} state.
+ * @param module the module instance
+ */
+ public void stop(Module module) {
+
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/ActionReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/ActionReporter.java
new file mode 100644
index 0000000..48e47a4
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/ActionReporter.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.common;
+
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import org.glassfish.api.ActionReport;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+/**
+ * Superclass for common ActionReport extension.
+ *
+ * @author Jerome Dochez
+ */
+public abstract class ActionReporter extends ActionReport {
+
+ protected Throwable exception = null;
+ protected String actionDescription = null;
+ protected List<ActionReporter> subActions = new ArrayList<ActionReporter>();
+ protected ExitCode exitCode = ExitCode.SUCCESS;
+ protected MessagePart topMessage = new MessagePart();
+ protected String contentType = "text/html";
+
+ public static final String EOL_MARKER = "%%%EOL%%%";
+
+ /** Creates a new instance of HTMLActionReporter */
+ public ActionReporter() {
+ }
+
+ public void setFailure() {
+ setActionExitCode(ExitCode.FAILURE);
+ }
+
+ public boolean isFailure() {
+ return getActionExitCode() == ExitCode.FAILURE;
+ }
+
+ public void setWarning() {
+ setActionExitCode(ExitCode.WARNING);
+ }
+
+ public boolean isWarning() {
+ return getActionExitCode() == ExitCode.WARNING;
+ }
+
+ public boolean isSuccess() {
+ return getActionExitCode() == ExitCode.SUCCESS;
+ }
+
+ public void setSuccess() {
+ setActionExitCode(ExitCode.SUCCESS);
+ }
+
+ @Override
+ public void setActionDescription(String message) {
+ this.actionDescription = message;
+ }
+
+ public String getActionDescription() {
+ return actionDescription;
+ }
+
+ @Override
+ public void setFailureCause(Throwable t) {
+ this.exception = t;
+ }
+ @Override
+ public Throwable getFailureCause() {
+ return exception;
+ }
+
+ @Override
+ public MessagePart getTopMessagePart() {
+ return topMessage;
+ }
+
+ @Override
+ public ActionReport addSubActionsReport() {
+ ActionReporter subAction;
+ try {
+ subAction = this.getClass().newInstance();
+ } catch (IllegalAccessException ex) {
+ return null;
+ } catch (InstantiationException ex) {
+ return null;
+ }
+ subActions.add(subAction);
+ return subAction;
+ }
+
+ @Override
+ public List<ActionReporter> getSubActionsReport() {
+ return subActions;
+ }
+
+ @Override
+ public void setActionExitCode(ExitCode exitCode) {
+ this.exitCode = exitCode;
+ }
+
+ @Override
+ public ExitCode getActionExitCode() {
+ return exitCode;
+ }
+
+ @Override
+ public void setMessage(String message) {
+ topMessage.setMessage(message);
+ }
+
+ @Override
+ public void appendMessage(String message) {
+ topMessage.appendMessage(message);
+ }
+
+ @Override
+ public String getMessage() {
+ return topMessage.getMessage();
+ }
+
+
+ @Override
+ public void setMessage(InputStream in) {
+ try {
+ if(in == null)
+ throw new NullPointerException("Internal Error - null InputStream");
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ copyStream(in, baos);
+ setMessage(baos.toString());
+ }
+ catch (Exception ex) {
+ setActionExitCode(ExitCode.FAILURE);
+ setFailureCause(ex);
+ }
+ }
+
+ private void copyStream(InputStream in, OutputStream out) throws IOException {
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) >= 0) {
+ out.write(buf, 0, len);
+ }
+
+ out.close();
+ in.close();
+ }
+
+ /**
+ * Returns the content type to be used in sending the response back to
+ * the client/caller.
+ * <p>
+ * This is the default type. Specific subclasses of ActionReporter might
+ * override the method to return a different valid type.
+ * @return content type to be used in formatting the command response to the client
+ */
+ @Override
+ public String getContentType() {
+ return contentType;
+ }
+ @Override
+ public void setContentType(String s) {
+ contentType = s;
+ }
+
+ /** Returns combined messages. Meant mainly for long running
+ * operations where some of the intermediate steps can go wrong, although
+ * overall operation succeeds. Does nothing if either of the arguments are null.
+ * The traversal visits the message of current reporter first. The various
+ * parts of the message are separated by EOL_MARKERs.
+ * <p>
+ * Note: This method is a recursive implementation.
+ * @param aReport a given (usually top-level) ActionReporter instance
+ * @param sb StringBuilder instance that contains all the messages
+ */
+ public void getCombinedMessages(ActionReporter aReport, StringBuilder sb) {
+ if (aReport == null || sb == null)
+ return;
+ String mainMsg = ""; //this is the message related to the topMessage
+ String failMsg; //this is the message related to failure cause
+ // Other code in the server may write something like report.setMessage(exception.getMessage())
+ // and also set report.setFailureCause(exception). We need to avoid the duplicate message.
+ if (aReport.getMessage() != null && aReport.getMessage().length() != 0) {
+ mainMsg = aReport.getMessage();
+ String format = "{0}";
+ if (ActionReport.ExitCode.WARNING.equals(aReport.getActionExitCode())) {
+ LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ActionReporter.class);
+ format = localStrings.getLocalString("flag.message.as.warning", "Warning: {0}");
+ }
+ if (ActionReport.ExitCode.FAILURE.equals(aReport.getActionExitCode())) {
+ LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ActionReporter.class);
+ format = localStrings.getLocalString("flag.message.as.failure", "Failure: {0}");
+ }
+ if (sb.length() > 0) sb.append(EOL_MARKER);
+ sb.append(MessageFormat.format(format,mainMsg));
+ }
+ if (aReport.getFailureCause() != null && aReport.getFailureCause().getMessage() != null && aReport.getFailureCause().getMessage().length() != 0) {
+ failMsg = aReport.getFailureCause().getMessage();
+ if (!failMsg.equals(mainMsg)) {
+ if (sb.length() > 0) sb.append(EOL_MARKER);
+ sb.append(failMsg);
+ }
+ }
+ for (ActionReporter sub : aReport.subActions) {
+ getCombinedMessages(sub, sb);
+ }
+ }
+
+ @Override
+ public boolean hasSuccesses() {
+ return has(this,ExitCode.SUCCESS);
+ }
+
+ @Override
+ public boolean hasWarnings() {
+ return has(this,ExitCode.WARNING);
+ }
+
+ @Override
+ public boolean hasFailures() {
+ return has(this,ExitCode.FAILURE);
+ }
+
+ private static boolean has(ActionReporter ar, ExitCode value) {
+ if (null != ar.exitCode && ar.exitCode.equals(value)) {
+ return true;
+ }
+ Queue<ActionReporter> q = new LinkedList<ActionReporter>();
+ q.addAll(ar.subActions);
+ while (!q.isEmpty()) {
+ ActionReporter lar = q.remove();
+ ExitCode ec = lar.getActionExitCode();
+ if (null != ec && ec.equals(value)) {
+ return true;
+ } else {
+ q.addAll(lar.subActions);
+ }
+ }
+ return false;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/BooleanLatch.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/BooleanLatch.java
new file mode 100644
index 0000000..20efea2
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/BooleanLatch.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.common;
+
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+/**
+ * Acts like a CountDownLatch except that it only requires a single signal to fire.
+ * Because a latch is non-exclusive, it uses the shared acquire and release methods.
+ *
+ * @author Jerome Dochez
+ */
+public class BooleanLatch extends AbstractQueuedSynchronizer {
+ public boolean isSignalled() { return getState() != 0; }
+
+ public int tryAcquireShared(int ignore) {
+ return isSignalled()? 1 : -1;
+ }
+
+ public boolean tryReleaseShared(int ignore) {
+ setState(1);
+ return true;
+ }
+ }
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/DoNothingActionReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/DoNothingActionReporter.java
new file mode 100644
index 0000000..1dae843
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/DoNothingActionReporter.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.common;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * PlainTextActionReporter is being used as a fake ActionReporter when one is
+ * required. It is confusing since PTAR does special things.
+ * THis one does exactly what it advertises doing in its name!
+ * @author Byron Nevins
+ */
+public class DoNothingActionReporter extends ActionReporter{
+
+ @Override
+ public void writeReport(OutputStream os) throws IOException {
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/HTMLActionReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/HTMLActionReporter.java
new file mode 100644
index 0000000..5b959e8
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/HTMLActionReporter.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.common;
+
+import org.jvnet.hk2.annotations.Service;
+
+import org.glassfish.hk2.api.PerLookup;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ *
+ * @author dochez
+ */
+@Service(name = "html")
+@PerLookup
+public class HTMLActionReporter extends ActionReporter {
+
+ /** Creates a new instance of HTMLActionReporter */
+ public HTMLActionReporter() {
+ }
+
+ @Override
+ public void writeReport(OutputStream os) throws IOException {
+ PrintWriter writer = new PrintWriter(os);
+ writer.print("<html><head/>");
+ writer.println("<body>" +
+ "<h1>GlassFish " + actionDescription + " command report</h1>" +
+ "<br><br>");
+ writer.println("Exit Code : " + this.exitCode);
+ writer.println("<hr>");
+ write(2, topMessage, writer);
+ writer.println("<hr>");
+ if (exception!=null) {
+ writer.println("Exception raised during operation : <br>");
+ writer.println("<pre>");
+ exception.printStackTrace(writer);
+ writer.println("</pre>");
+ }
+ if (subActions.size()>0) {
+ writer.println("There are " + subActions.size() + " sub operations");
+ }
+ writer.print("</body></html>");
+ writer.flush();
+ }
+
+ private void write(int level, MessagePart part, PrintWriter writer) {
+ String mess = part.getMessage();
+ if (mess==null){
+ mess = "";//better than a null string output
+ }
+ if (level>6) {
+ writer.println(mess);
+ } else {
+ writer.println("<h" + level + ">" + mess + "</h" + level + ">");
+ }
+ write(part.getProps(), writer);
+
+ for (MessagePart child : part.getChildren()) {
+ write(level+1, child, writer);
+ }
+ }
+
+ private void write(Properties props, PrintWriter writer) {
+ if (props==null || props.size()==0) {
+ return;
+ }
+ writer.println("<table border=\"1\">");
+ for (Map.Entry entry : props.entrySet()) {
+ writer.println("<tr>");
+ writer.println("<td>" + entry.getKey() + "</td>");
+ writer.println("<td>" + entry.getValue() + "</td>");
+ writer.println("</tr>");
+ }
+ writer.println("</table>");
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/JsonActionReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/JsonActionReporter.java
new file mode 100644
index 0000000..4d0e088
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/JsonActionReporter.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.common;
+
+import org.jvnet.hk2.annotations.Service;
+
+import org.glassfish.hk2.api.PerLookup;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * Writes command output to a json stream
+ *
+ * @author Ludovic Champenois
+ */
+@Service(name = "json")
+@PerLookup
+public class JsonActionReporter extends ActionReporter {
+
+ /*
+ top is true only for the first toplevel message to emit more data like
+ * command name and exit_code of the command
+ *
+ */
+ private boolean top = true;
+
+ /** Creates a new instance of JsonActionReporter */
+ public JsonActionReporter() {
+ }
+
+ @Override
+ public void writeReport(OutputStream os) throws IOException {
+ PrintWriter writer = new PrintWriter(os);
+
+ write(topMessage, writer);
+ if (exception != null) {
+ writer.println("Exception raised during operation : <br>");
+ exception.printStackTrace(writer);
+ }
+ if (subActions.size() > 0) {
+ writer.println(quote(", number_subactions") + ":" + quote("" + subActions.size()));
+ }
+ writer.flush();
+ }
+
+ private void write(MessagePart part, PrintWriter writer) {
+ writer.println("{ " + quote("name") + ":" + quote(part.getMessage()));
+ if (top) {
+ writer.println(", " + quote("command") + ":" + quote(actionDescription));
+ writer.println(", " + quote("exit_code") + ":" + quote("" + this.exitCode));
+ top = false;
+ }
+ writeProperties(part.getProps(), writer);
+ boolean first = true;
+ for (MessagePart child : part.getChildren()) {
+ if (first == true) {
+ writer.println(", " + quote("result") + " : [");
+ } else {
+ writer.println(",");
+
+ }
+ first = false;
+ write(child, writer);
+
+ }
+ if (first == false) { //close the array
+
+ writer.println("]");
+ }
+
+ writer.println("}");
+
+ }
+
+ private void writeProperties(Properties props, PrintWriter writer) {
+ if (props == null || props.size() == 0) {
+ return;
+ }
+ StringBuilder result = new StringBuilder(",");
+ result.append(quote("properties")).append(" : {");
+ String sep = "";
+ for (Map.Entry entry : props.entrySet()) {
+ String line = quote("" + entry.getKey()) + " : ";
+ Object value = entry.getValue();
+ if (value instanceof List) {
+ line += encodeList((List)value);
+ } else if (value instanceof Map) {
+ line += encodeMap((Map)value);
+ } else {
+ line += quote("" + value.toString());
+ }
+ result.append(sep).append(line);
+
+ sep = ",";
+ }
+ writer.println(result.append("}").toString());
+
+ }
+
+ private String encodeList (List list) {
+ StringBuilder result = new StringBuilder("[");
+ String sep = "";
+ for (Object entry : list) {
+ if (entry instanceof List) {
+ result.append(sep).append(encodeList((List)entry));
+ } else if (entry instanceof Map) {
+ result.append(sep).append(encodeMap((Map)entry));
+ } else {
+ result.append(sep).append(quote (entry.toString()));
+ }
+
+ sep = ",";
+ }
+ return result.append("]").toString();
+ }
+
+ private String encodeMap (Map map) {
+ StringBuilder result = new StringBuilder("{");
+ String sep = "";
+ for (Map.Entry entry : (Set<Map.Entry>)map.entrySet()) {
+ String key = entry.getKey().toString();
+ Object value = entry.getValue();
+ result.append(sep).append(quote(key)).append(":");
+
+ if (value instanceof List) {
+ result.append(encodeList((List) value));
+ } else if (value instanceof Map) {
+ result.append(encodeMap((Map) value));
+ } else {
+ result.append(quote(value.toString()));
+ }
+ sep = ",";
+ }
+
+ return result.append("}").toString();
+ }
+
+ /**
+ * Produce a string in double quotes with backslash sequences in all the
+ * right places.
+ */
+ private String quote(String string) {
+ if (string == null || string.length() == 0) {
+ return "\"\"";
+ }
+
+ char b;
+ char c = 0;
+ int i;
+ int len = string.length();
+ StringBuilder sb = new StringBuilder(len + 4);
+ String t;
+
+ sb.append('"');
+ for (i = 0; i < len; i += 1) {
+ b = c;
+ c = string.charAt(i);
+ switch (c) {
+ case '\\':
+ case '"':
+ sb.append('\\');
+ sb.append(c);
+ break;
+ case '/':
+ if (b == '<') {
+ sb.append('\\');
+ }
+ sb.append(c);
+ break;
+ case '\b':
+ sb.append("\\b");
+ break;
+ case '\t':
+ sb.append("\\t");
+ break;
+ case '\n':
+ sb.append("\\n");
+ break;
+ case '\f':
+ sb.append("\\f");
+ break;
+ case '\r':
+ sb.append("\\r");
+ break;
+ default:
+ if (c < ' ') {
+ t = "000" + Integer.toHexString(c);
+ sb.append("\\u" + t.substring(t.length() - 4));
+ } else {
+ sb.append(c);
+ }
+ }
+ }
+ sb.append('"');
+ return sb.toString();
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/LocalStrings.properties b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/LocalStrings.properties
new file mode 100644
index 0000000..aaf7112
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/LocalStrings.properties
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+
+
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+flag.message.as.warning={0}
+flag.message.as.failure={0}
+get.mon.no.data=No monitoring data to report.
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/PlainTextActionReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/PlainTextActionReporter.java
new file mode 100644
index 0000000..32fd550
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/PlainTextActionReporter.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.common;
+
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import static com.sun.enterprise.util.StringUtils.ok;
+import java.util.*;
+import org.jvnet.hk2.annotations.Service;
+
+import org.glassfish.hk2.api.PerLookup;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.OutputStream;
+
+/**
+ *
+ * @author Byron Nevins
+ */
+@Service(name = "plain")
+@PerLookup
+public class PlainTextActionReporter extends ActionReporter {
+
+ public static final String MAGIC = "PlainTextActionReporter";
+
+ @Override
+ public void writeReport(OutputStream os) throws IOException {
+ // The caller will read MAGIC and the next characters for success/failure
+ // everything after the HEADER_END is good data
+ writer = new PrintWriter(os);
+ writer.print(MAGIC);
+ if (isFailure()) {
+ writer.print("FAILURE");
+ Throwable t = getFailureCause();
+
+ if (t != null) {
+ writer.print(t);
+ }
+ }
+ else {
+ writer.print("SUCCESS");
+ }
+
+ StringBuilder finalOutput = new StringBuilder();
+ getCombinedMessages(this, finalOutput);
+ String outs = finalOutput.toString();
+
+ if (!ok(outs)) {
+ // we want at least one line of output. Otherwise RemoteResponseManager
+ // will consider this an error. It is NOT an error there just is no data to report.
+ LocalStringManagerImpl localStrings = new LocalStringManagerImpl(PlainTextActionReporter.class);
+ writer.print(localStrings.getLocalString("get.mon.no.data", "No monitoring data to report."));
+ writer.print("\n"); // forces an error to manifest constructor
+ }
+ else
+ writer.print(outs);
+
+ writer.flush();
+ }
+
+ @Override
+ public String getContentType() {
+ return "text/plain";
+ }
+
+ /**
+ * Append the string to the internal buffer -- not to the internal message string!
+ * @param s the string to append
+ */
+ @Override
+ final public void appendMessage(String s) {
+ sb.append(s);
+ }
+
+ /**
+ * Append the string to the internal buffer and add a linefeed like 'println'
+ * @param s the string to append
+ */
+ final public void appendMessageln(String s) {
+ sb.append(s).append('\n');
+ }
+
+ @Override
+ public void setMessage(String message) {
+ super.setMessage(message);
+ sb.delete(0, sb.length());
+ appendMessage(message);
+ }
+
+ public final String getMessage() {
+ return sb.toString();
+ }
+
+ @Override
+ public void getCombinedMessages(ActionReporter aReport, StringBuilder out) {
+ if(aReport == null || !(aReport instanceof PlainTextActionReporter) )
+ throw new RuntimeException("Internal Error: Sub reports are different types than parent report.");
+ // guaranteed safe above.
+ PlainTextActionReporter ptr = (PlainTextActionReporter) aReport;
+ String s = ptr.getOutputData();
+
+ if (ok(s)) {
+ if (out.length() > 0)
+ out.append('\n');
+
+ out.append(s);
+ }
+
+ for (ActionReporter ar : aReport.subActions) {
+ getCombinedMessages(ar, out);
+ }
+ }
+
+ private String getOutputData() {
+ if (superSimple(topMessage))
+ return simpleGetOutputData();
+ else
+ return notSoSimpleGetOutputData();
+ }
+
+ private boolean superSimple(MessagePart part) {
+ // this is mainly here for backward compatability for when this Reporter
+ // only wrote out the main message.
+ List<MessagePart> list = part.getChildren();
+ Properties props = part.getProps();
+ boolean hasChildren = (list != null && !list.isEmpty());
+ boolean hasProps = (props != null && props.size() > 0);
+
+ // return true if we are very very simple!
+ return !hasProps && !hasChildren;
+ }
+
+ private String simpleGetOutputData() {
+ StringBuilder out = new StringBuilder();
+ String tm = topMessage.getMessage();
+ String body = sb.toString();
+
+ if (ok(tm) && !ok(body))
+ body = tm;
+
+ if (ok(body)) {
+ out.append(body);
+ }
+
+ return out.toString();
+ }
+
+ private String notSoSimpleGetOutputData() {
+ StringBuilder out = new StringBuilder();
+
+ if (ok(actionDescription)) {
+ out.append("Description: ").append(actionDescription);
+ }
+
+ write("", topMessage, out);
+ return out.toString();
+ }
+
+ private void write(String indent, MessagePart part, StringBuilder out) {
+ out.append(indent).append(part.getMessage()).append('\n');
+ write(indent + INDENT, part.getProps(), out);
+
+ for (MessagePart child :
+ part.getChildren()) {
+ write(indent + INDENT, child, out);
+ }
+ }
+
+ private void write(String indent, Properties props, StringBuilder out) {
+ if (props == null || props.size() <= 0) {
+ return;
+ }
+
+ for (Map.Entry<Object, Object> entry :
+ props.entrySet()) {
+ String key = "" + entry.getKey();
+ String val = "" + entry.getValue();
+ out.append(indent).append('[').append(key).append('=').append(val).append("\n");
+ }
+ }
+ private transient PrintWriter writer;
+ private static final String INDENT = " ";
+ private final StringBuilder sb = new StringBuilder();
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/PropsFileActionReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/PropsFileActionReporter.java
new file mode 100644
index 0000000..15792e7
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/PropsFileActionReporter.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.common;
+
+import com.sun.enterprise.util.StringUtils;
+import java.io.UnsupportedEncodingException;
+import java.util.*;
+import org.jvnet.hk2.annotations.Service;
+
+import org.glassfish.hk2.api.PerLookup;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
+import java.util.Map;
+
+/**
+ * Action reporter to a manifest file
+ * @author Jerome Dochez
+ */
+@Service(name = "hk2-agent")
+@PerLookup
+public class PropsFileActionReporter extends ActionReporter {
+
+ @Override
+ public void setMessage(String message) {
+ super.setMessage(encodeEOL(message));
+ }
+
+ @Override
+ public void writeReport(OutputStream os) throws IOException {
+
+ Manifest out = new Manifest();
+ Attributes mainAttr = out.getMainAttributes();
+ mainAttr.put(Attributes.Name.SIGNATURE_VERSION, "1.0");
+ mainAttr.putValue("exit-code", exitCode.toString());
+ mainAttr.putValue("use-main-children-attribute", Boolean.toString(useMainChildrenAttr));
+
+ if (exitCode == ExitCode.FAILURE) {
+ writeCause(mainAttr);
+ }
+
+ writeReport(null, topMessage, out, mainAttr);
+ out.write(os);
+ }
+
+ public void writeReport(String prefix, MessagePart part, Manifest m, Attributes attr) {
+ //attr.putValue("message", part.getMessage());
+ StringBuilder sb = new StringBuilder();
+ getCombinedMessages(this, sb);
+ attr.putValue("message", sb.toString());
+ if (part.getProps().size() > 0) {
+ String keys = null;
+ for (Map.Entry entry : part.getProps().entrySet()) {
+ String key = fixKey(entry.getKey().toString());
+ keys = (keys == null ? key : keys + ";" + key);
+ attr.putValue(key + "_name", entry.getKey().toString());
+ attr.putValue(key + "_value", encodeEOL(entry.getValue().toString()));
+ }
+
+ attr.putValue("keys", keys);
+ }
+ if (part.getChildren().size() > 0) {
+ attr.putValue("children-type", part.getChildrenType());
+ attr.putValue("use-main-children-attribute", "true");
+ StringBuilder keys = null;
+ for (MessagePart child : part.getChildren()) {
+ // need to URL encode a ';' as %3B because it is used as a
+ // delimiter
+ String cm = child.getMessage();
+ if (cm != null) {
+ try {
+ cm = URLEncoder.encode(cm, "UTF-8");
+ } catch (UnsupportedEncodingException ex) {
+ // ignore - leave cm as it is
+ }
+ }
+ String newPrefix = (prefix == null ? cm : prefix + "." + cm);
+
+ if(keys == null)
+ keys = new StringBuilder();
+ else
+ keys.append(';');
+
+ if(newPrefix != null)
+ keys.append(newPrefix);
+
+ Attributes childAttr = new Attributes();
+ m.getEntries().put(newPrefix, childAttr);
+ writeReport(newPrefix, child, m, childAttr);
+ }
+ attr.putValue("children", keys.toString());
+ }
+ }
+
+ private void writeCause(Attributes mainAttr) {
+ Throwable t = getFailureCause();
+
+ if (t == null) {
+ return;
+ }
+
+ String causeMessage = t.toString();
+ mainAttr.putValue("cause", causeMessage);
+ }
+
+ /* Issue 5918 Keep output sorted. If set to true ManifestManager will grab
+ * "children" from main attributes. "children" is in original order of
+ * output set by server-side
+ */
+ public void useMainChildrenAttribute(boolean useMainChildrenAttr) {
+ this.useMainChildrenAttr = useMainChildrenAttr;
+ }
+
+ private String fixKey(String key) {
+ // take a look at the javadoc -- java.util.jar.Attributes.Name
+ // < 70 chars in length and [a-zA-Z0-9_-]
+ // then you can see in the code above that we take the key and add
+ // _value to it. So we simply hack it off at 63 characters.
+ // We also replace "bad" characters with "_". Note that asadmin will
+ // display the correct real name.
+
+ if (!StringUtils.ok(key)) {
+ return key; // GIGO!
+ }
+ StringBuilder sb = new StringBuilder();
+ boolean wasChanged = false;
+ int len = key.length();
+
+ if (len > LONGEST) {
+ len = LONGEST;
+ wasChanged = true;
+ }
+
+ for (int i = 0; i < len; i++) {
+ char c = key.charAt(i);
+
+ if (!isValid(c)) {
+ wasChanged = true;
+ sb.append('_');
+ } else {
+ sb.append(c);
+ }
+ }
+
+ if (!wasChanged) {
+ return key;
+ }
+
+ String fixedName = sb.toString();
+
+ if (fixedNames.add(fixedName)) {
+ return fixedName;
+ }
+
+ // perhaps they are using huge long names that differ just at the end?
+ return doubleFixName(fixedName);
+ }
+
+ private String doubleFixName(String s) {
+ // Yes, this is a nightmare!
+ int len = s.length();
+
+ if (len > LONGEST - 5) {
+ s = s.substring(0, LONGEST - 5);
+ }
+
+ for (int i = 0; i < 10000; i++) {
+ String num = String.format("%05d", i);
+ String ret = s + num;
+
+ if (fixedNames.add(ret)) {
+ return ret;
+ }
+ }
+ // Wow!!!
+ throw new IllegalArgumentException("Could not come up with a unique name after 10000 attempts!!");
+ }
+
+ private static boolean isValid(char c) {
+ return isAlpha(c) || isDigit(c) || c == '_' || c == '-';
+ }
+
+ private static boolean isAlpha(char c) {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+ }
+
+ private static boolean isDigit(char c) {
+ return c >= '0' && c <= '9';
+ }
+ private static String encodeEOL(String m) {
+ if (m != null) {
+ m = m.replace("\n", EOL_MARKER).replace(System.getProperty("line.separator"), EOL_MARKER);
+ }
+ return m;
+ }
+ private boolean useMainChildrenAttr = false;
+ private Set<String> fixedNames = new TreeSet<String>();
+ private static final int LONGEST = 62;
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/XMLActionReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/XMLActionReporter.java
new file mode 100644
index 0000000..8a0f6fe
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/XMLActionReporter.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.common;
+
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.jvnet.hk2.annotations.Service;
+
+import org.glassfish.hk2.api.PerLookup;
+
+/**
+ * Represents the action report as XML like this:
+ * <br>
+ * <!--
+ * Apologies for the formatting - it's necessary for the JavaDoc to be readable
+ * If you are using NetBeans, for example, click anywhere in this comment area to see
+ * the document example clearly in the JavaDoc preview
+ * -->
+ * <code>
+ * <br><action-report description="xxx" exit-code="xxx" [failure-cause="xxx"]>
+ * <br> <message-part message="xxx">
+ * <br> <property name="xxx" value="xxx"/>
+ * <br> ...
+ * <br> <message-part message="xxx" type="xxx">
+ * <br> ...
+ * <br> </message-part>
+ * <br> </message-part>
+ * <br> <action-report ...> [for subactions]
+ * <br> ...
+ * <br> </action-report>
+ * <br></action-report>
+ * </code>
+ *
+ * @author tjquinn
+ */
+@Service(name="xml")
+@PerLookup
+public class XMLActionReporter extends ActionReporter {
+
+ @Override
+ public void writeReport(OutputStream os) {
+ try {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document d = db.newDocument();
+
+ d.appendChild(writeActionReport(d, this));
+ writeXML(d, os);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ /**
+ * Creates a new Element representing the XML content describing an
+ * action report. Invokes itself recursively to capture information
+ * about any subactions.
+ * @param owningDocument Document which will own all generated XML content
+ * @param report the ActionReporter to convert to XML content
+ * @return Element for the specified ActionReporter (and any sub-reports)
+ */
+ private Element writeActionReport(Document owningDocument, ActionReporter report) {
+ Element result = owningDocument.createElement("action-report");
+ result.setAttribute("description", report.actionDescription);
+ result.setAttribute("exit-code", report.getActionExitCode().name());
+ if (exception != null) {
+ result.setAttribute("failure-cause", exception.getLocalizedMessage());
+ }
+
+ writePart(result, report.getTopMessagePart(), null);
+ for (ActionReporter subReport : report.subActions) {
+ result.appendChild(writeActionReport(owningDocument, subReport));
+ }
+ return result;
+ }
+
+ @Override
+ public String getContentType() {
+ return "text/xml";
+ }
+
+ private void writePart(Element actionReport, MessagePart part, String childType) {
+ Document d = actionReport.getOwnerDocument();
+ Element messagePart = d.createElement("message-part");
+ actionReport.appendChild(messagePart);
+ if (childType != null) {
+ messagePart.setAttribute("type", childType);
+ }
+
+ for (Map.Entry prop : part.getProps().entrySet()) {
+ Element p = d.createElement("property");
+ messagePart.appendChild(p);
+ p.setAttribute("name", prop.getKey().toString());
+ Object value = prop.getValue();
+ if (value instanceof List) {
+ addListElement(p, (List)value);
+ } else if (value instanceof Map) {
+ addMapElement(p, (Map)value);
+ } else {
+ p.setAttribute("value", prop.getValue().toString());
+ }
+ }
+ messagePart.setAttribute("message", part.getMessage());
+ for (MessagePart subPart : part.getChildren()) {
+ writePart(messagePart, subPart, subPart.getChildrenType());
+ }
+ }
+
+ private void addListElement(Element parent, List list) {
+ Document d = parent.getOwnerDocument();
+ Element listElement = d.createElement("list");
+ parent.appendChild(listElement);
+
+ for (Object entry : list) {
+ Element entryElement = d.createElement("entry");
+ listElement.appendChild(entryElement);
+ if (entry instanceof List) {
+ addListElement(entryElement, (List) entry);
+ } else if (entry instanceof Map) {
+ addMapElement(entryElement, (Map) entry);
+ } else {
+ entryElement.setAttribute("value", entry.toString());
+ }
+ }
+ }
+
+ private void addMapElement(Element parent, Map map) {
+ Document d = parent.getOwnerDocument();
+ Element mapElement = d.createElement("map");
+ parent.appendChild(mapElement);
+
+ for (Map.Entry entry : (Set<Map.Entry>)map.entrySet()) {
+ Element entryElement = d.createElement("entry");
+ String key = entry.getKey().toString();
+ Object value = entry.getValue();
+ mapElement.appendChild(entryElement);
+ entryElement.setAttribute("key", key);
+
+ if (value instanceof List) {
+ addListElement(entryElement, (List) value);
+ } else if (value instanceof Map) {
+ addMapElement(entryElement, (Map) value);
+ } else {
+ entryElement.setAttribute("value", value.toString());
+ }
+ }
+ }
+
+ private void writeXML(Document doc, OutputStream os) throws TransformerConfigurationException, TransformerException {
+ Source source = new DOMSource(doc);
+
+ Result result = new StreamResult(os);
+
+ Transformer xformer = TransformerFactory.newInstance().newTransformer();
+ xformer.transform(source, result);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/XMLContentActionReporter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/XMLContentActionReporter.java
new file mode 100644
index 0000000..14112c9
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/common/XMLContentActionReporter.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.common;
+
+import java.io.OutputStream;
+import java.util.Map;
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.jvnet.hk2.annotations.Service;
+
+import org.glassfish.hk2.api.PerLookup;
+
+/**
+ * Represents the action report as XML like this:
+ * <br>
+ * <!--
+ * Apologies for the formatting - it's necessary for the JavaDoc to be readable
+ * If you are using NetBeans, for example, click anywhere in this comment area to see
+ * the document example clearly in the JavaDoc preview
+ * -->
+ * <code>
+ * <br><action-report description="xxx" exit-code="xxx" [failure-cause="xxx"]>
+ * <br> <message-part message="">
+ * <br> <property name="xxx" value="xxx"/>
+ * <br> ...
+ * <br> <<i>child-type</i> <i>property</i>="value"/>
+ * <br> ...
+ * <br> </<i>child-type</i>>
+ * <br> </message-part>
+ * <br> </message-part>
+ * <br></action-report>
+ * </code>
+ *
+ * Currently this is used to return the metadata for a command, although
+ * it could be used more generally to return XML content. In the general
+ * case the action-report and message-part elements ought to be removed.
+ *
+ * @author tjquinn
+ * @author Bill Shannon
+ */
+@Service(name="metadata") // XXX - need a better mapping
+@PerLookup
+public class XMLContentActionReporter extends ActionReporter {
+
+ public void writeReport(OutputStream os) {
+ try {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+
+ Document d = db.newDocument();
+
+ d.appendChild(writeActionReport(d, this));
+ writeXML(d, os);
+ } catch (ParserConfigurationException pex) {
+ throw new RuntimeException(pex);
+ } catch (TransformerException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Creates a new Element representing the XML content describing an
+ * action report. Invokes itself recursively to capture information
+ * about any subactions.
+ * @param owningDocument Document which will own all generated XML content
+ * @param report the ActionReporter to convert to XML content
+ * @return Element for the specified ActionReporter (and any sub-reports)
+ */
+ private Element writeActionReport(Document owningDocument,
+ ActionReporter report) {
+ Element result = owningDocument.createElement("action-report");
+ result.setAttribute("description", report.actionDescription);
+ result.setAttribute("exit-code", report.getActionExitCode().name());
+ if (exception != null) {
+ result.setAttribute("failure-cause",
+ exception.getLocalizedMessage());
+ }
+
+ writePart(result, report.getTopMessagePart(), null);
+ for (ActionReporter subReport : report.subActions) {
+ result.appendChild(writeActionReport(owningDocument, subReport));
+ }
+ return result;
+ }
+
+ @Override
+ public String getContentType() {
+ return "text/xml";
+ }
+
+ private void writePart(Element actionReport, MessagePart part,
+ String childType) {
+ Document d = actionReport.getOwnerDocument();
+ Element messagePart = d.createElement("message-part");
+ actionReport.appendChild(messagePart);
+ if (childType != null) {
+ messagePart.setAttribute("type", childType);
+ }
+
+ for (Map.Entry prop : part.getProps().entrySet()) {
+ Element p = d.createElement("property");
+ messagePart.appendChild(p);
+ p.setAttribute("name", prop.getKey().toString());
+ p.setAttribute("value", prop.getValue().toString());
+ }
+ messagePart.setAttribute("message", part.getMessage());
+
+ for (MessagePart subPart : part.getChildren())
+ writeSubPart(messagePart, subPart, subPart.getChildrenType());
+ }
+
+ /**
+ * Write out all the sub-parts as XML elements where the
+ * "childType" is the name of the XML element and the properties
+ * are attributes of the element. Recurse for any subparts.
+ */
+ private void writeSubPart(Element actionReport, MessagePart part,
+ String childType) {
+ Document d = actionReport.getOwnerDocument();
+ Element messagePart = d.createElement(childType);
+ actionReport.appendChild(messagePart);
+
+ for (Map.Entry prop : part.getProps().entrySet()) {
+ messagePart.setAttribute(prop.getKey().toString(),
+ prop.getValue().toString());
+ }
+ for (MessagePart subPart : part.getChildren())
+ writeSubPart(messagePart, subPart, subPart.getChildrenType());
+ }
+
+ /**
+ * Write the XML document to the output stream.
+ *
+ * @param doc the XML document
+ * @param os the output stream
+ * @throws TransformerException if anything goes wrong
+ */
+ private void writeXML(Document doc, OutputStream os)
+ throws TransformerException {
+ Source source = new DOMSource(doc);
+
+ Result result = new StreamResult(os);
+
+ Transformer xformer = TransformerFactory.newInstance().newTransformer();
+ xformer.transform(source, result);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/APIClassLoaderServiceImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/APIClassLoaderServiceImpl.java
new file mode 100644
index 0000000..8fc3082
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/APIClassLoaderServiceImpl.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.module.Module;
+import com.sun.enterprise.module.ModuleLifecycleListener;
+import com.sun.enterprise.module.ModuleState;
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.module.common_impl.CompositeEnumeration;
+import java.io.IOException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * This class is responsible for creating a ClassLoader that can
+ * load classes exported by the system for public use. We call those classes public APIs and
+ * the corresponding class loader is called APIClassLoader.
+ * Such classes include Java EE API, AMX API, appserv-ext API, etc.
+ * CommonClassLoader delegates to this class loader.
+ * This class has a punch-in mechanism to do special handling of META-INF/mailcap and META-INF/services resources.
+ *
+ * @author Sanjeeb.Sahoo@Sun.COM
+ */
+@Service
+public class APIClassLoaderServiceImpl implements PostConstruct {
+
+ /*
+ * Implementation Note:
+ * 1. This class currently depends on a special which is configured such that it can load all public APIs.
+ * The APIClassLoader is a wrapper around such a module's loader. This is how we are indepdendent of
+ * actual module system like OSGi. So far it has worked when we run in OSGi mode as well as when we run
+ * in a single classpath mode.
+ * 2. APIClassLoader maintains a blacklist, i.e., classes and resources that could not be loaded to avoid
+ * unnecessary delegation. It flushes that list everytime a new bundle is installed in the system.
+ * This takes care of performance problem in typical production use of GlassFish.
+ *
+ * TODO:
+ * 1. We need to add an upper threshold for blacklist to avoid excessive use of memory.
+ * 2. Externalize punch-in facility. We don't want to know about things like MAILCAP file in this class.
+ */
+
+ private ClassLoader theAPIClassLoader;
+
+ @Inject
+ ModulesRegistry mr;
+
+ /**
+ * This is the module that we delegate to.
+ */
+ private static final String APIExporterModuleName =
+ "GlassFish-Application-Common-Module"; // NOI18N
+ private static final String MAILCAP = "META-INF/mailcap";
+ private static final String META_INF_SERVICES = "META-INF/services/"; // NOI18N
+
+ private static final String PUNCHIN_MODULE_STATE_PROP =
+ "glassfish.kernel.apicl.punchin.module.state"; // NOI18N
+
+ // set to NEW to maintain backward compatibility. We should change it to RESOLVED after we have
+ // done enough testing to make susre there are no regressions.
+ public final ModuleState PUNCHIN_MODULE_STATE_DEFAULT_VALUE = ModuleState.NEW;
+
+ private static final Enumeration<URL> EMPTY_URLS = new Enumeration<URL>() {
+
+ public boolean hasMoreElements() {
+ return false;
+ }
+
+ public URL nextElement() {
+ throw new NoSuchElementException();
+ }
+ };
+ final static Logger logger = KernelLoggerInfo.getLogger();
+ private Module APIModule;
+
+ public void postConstruct() {
+ try {
+ createAPIClassLoader();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void createAPIClassLoader() throws IOException {
+
+ APIModule = mr.getModules(APIExporterModuleName).iterator().next();
+ assert (APIModule != null);
+ final ClassLoader apiModuleLoader = APIModule.getClassLoader();
+ /*
+ * We don't directly retrun APIModule's class loader, because
+ * that class loader does not delegate to the parent. Instead, it
+ * relies on OSGi bundle or some such module implementation to load the classes. That behavior is
+ * fine if we want to mimic underlying module system's classloading semantics. But, APIClassLoader has a
+ * slightly different requirement. It has to use classic delegation model as well so that
+ * deployed applications can use classes made available via extension class loader.
+ * Since the parent of bundle classloader will have glassfish launching classes, felix or any other
+ * OSGi framework classes and their dependencies, we don't want to delegate to such a class loader.
+ * Instead, we delegate to JRE's extension class loader if we don't find any class via APIModuleLoader.
+ * With this, user can actually embed a different version of Felix as part of their app.
+ */
+ theAPIClassLoader = new APIClassLoader(apiModuleLoader, getExtensionClassLoader());
+ logger.logp(Level.FINE, "APIClassLoaderService", "createAPIClassLoader",
+ "APIClassLoader = {0}", new Object[]{theAPIClassLoader});
+ }
+
+ private ClassLoader getExtensionClassLoader() {
+ if (System.getSecurityManager() != null) {
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return ClassLoader.getSystemClassLoader().getParent();
+ }
+ });
+ } else {
+ return ClassLoader.getSystemClassLoader().getParent();
+ }
+ }
+
+ public ClassLoader getAPIClassLoader() {
+ return theAPIClassLoader;
+ }
+
+ private class APIClassLoader extends ClassLoader {
+
+ // list of not found classes and resources.
+ // the string represents resource name, so foo/Bar.class for foo.Bar
+ private Set<String> blacklist;
+ private final ClassLoader apiModuleLoader;
+ private ModuleState punchInModuleState = ModuleState.valueOf(System.getProperty(PUNCHIN_MODULE_STATE_PROP,
+ PUNCHIN_MODULE_STATE_DEFAULT_VALUE.toString()));
+
+ /**
+ * This method takes two classloaders which is unusual. Both the class loaders are consulted,
+ * so they both are delegates, but depending on the class/resource being requested, one is preferred
+ * over the other. The second argument is the classic parent class loader, where as the first one
+ * is the module system gateway classloader. For all java.* names, we consult only the parent loader.
+ * For any other names, we first consult the gateway loader and then parent. See more comments in
+ * {@link #loadClass(String)} method implementation of this class.
+ * @param apiModuleLoader ClassLoader corresponding to the APIModule
+ * @param parent ClassLoader that's consulted for all java.* classes and for classes
+ * not found via apiModuleLoader
+ */
+ public APIClassLoader(ClassLoader apiModuleLoader, ClassLoader parent) {
+ super(parent);
+ this.apiModuleLoader = apiModuleLoader;
+ blacklist = new HashSet<String>();
+
+ // add a listener to manage blacklist in APIClassLoader
+ mr.register(new ModuleLifecycleListener() {
+ public void moduleInstalled(Module module) {
+ clearBlackList();
+ }
+
+ public void moduleResolved(Module module) {
+ }
+
+ public void moduleStarted(Module module) {
+ }
+
+ public void moduleStopped(Module module) {
+ }
+
+ public void moduleUpdated(Module module) {
+ clearBlackList();
+ }
+ });
+
+ }
+
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ return loadClass(name, false);
+ }
+
+ @Override
+ protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ // First check if we know this can't be loaded
+ final String resourceName = convertToResourceName(name);
+ if (isBlackListed(resourceName)) {
+ throw new ClassNotFoundException(name);
+ }
+
+ // Then check if the class has already been loaded
+ Class c = findLoadedClass(name);
+ if (c == null) {
+ if (!name.startsWith("java.")) { // java classes always come from parent
+ try {
+ c = apiModuleLoader.loadClass(name); // we ignore the resolution flag
+ } catch (ClassNotFoundException cnfe) {
+ // punch in. find the provider class, no matter where we are.
+ Module m = mr.getProvidingModule(name);
+ if (m != null) {
+ if(select(m)) {
+ return m.getClassLoader().loadClass(name); // abort search if we fail to load.
+ } else {
+ logger.logp(Level.FINE, "APIClassLoaderServiceImpl$APIClassLoader", "loadClass",
+ "Skipping loading {0} from module {1} as this module is not yet resolved.",
+ new Object[]{name, m});
+ }
+ }
+ }
+ }
+ if (c == null) {
+ // Call super class implementation which takes care of
+ // delegating to parent.
+ try {
+ c = super.loadClass(name, resolve);
+ } catch (ClassNotFoundException e) {
+ addToBlackList(resourceName);
+ throw e;
+ }
+ }
+ }
+ return c;
+ }
+
+ /**
+ * Select this module if it meets punch-in criteria. At this point of implementation, the criteria is
+ * very simple. It checks to see if the module's state is greater than equal to what is configured in
+ * {@link #punchInModuleState}.
+ *
+ * @param m
+ * @return
+ */
+ private boolean select(Module m) {
+ ModuleState state = m.getState();
+ return state.compareTo(punchInModuleState) >= 0 && state != ModuleState.ERROR;
+ }
+
+ @Override
+ public URL getResource(String name) {
+ if (isBlackListed(name)) return null;
+ URL url = null;
+ if (!name.startsWith("java/")) {
+ url = apiModuleLoader.getResource(name);
+ if (url != null) {
+ return url;
+ }
+
+ // now punch-ins for various cases that require special handling
+ if (name.equals(MAILCAP)) {
+ // punch in for META-INF/mailcap files.
+ // see issue #8426
+ for (Module m : mr.getModules()) {
+ if (!select(m)) continue;
+ if ((url = m.getClassLoader().getResource(name)) != null) {
+ return url;
+ }
+ }
+ } else if(name.startsWith(META_INF_SERVICES)) {
+ // punch in to find the service loader from any module
+ // If this is a META-INF/services lookup, search in every
+ // modules that we know of.
+ String serviceName = name.substring(
+ META_INF_SERVICES.length());
+
+ for( Module m : mr.getModules() ) {
+ if (!select(m)) continue;
+ List<URL> list = m.getMetadata().getDescriptors(
+ serviceName);
+ if(!list.isEmpty()) {
+ return list.get(0);
+ }
+ }
+ }
+ }
+ // Either requested resource belongs to java/ namespace or
+ // it was not found in any of the bundles, so call
+ // super class implementation which will delegate to parent.
+ url = super.getResource(name);
+ if (url == null) {
+ addToBlackList(name);
+ }
+ return url;
+ }
+
+ /**
+ * This method is required as {@link ClassLoader#getParent} is a privileged method
+ */
+ private ClassLoader getParent_() {
+ if (System.getSecurityManager() != null) {
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return getParent();
+ }
+ });
+ } else {
+ return getParent();
+ }
+ }
+
+ @Override
+ public Enumeration<URL> getResources(String name) throws IOException {
+ List<Enumeration<URL>> enumerators = new ArrayList<Enumeration<URL>>();
+ enumerators.add(findResources(name));
+ if (getParent_() != null) {
+ enumerators.add(getParent_().getResources(name));
+ }
+ return new CompositeEnumeration(enumerators);
+ }
+
+ // This method is needed to be compatible with ClassLoader implementation in IBM JRE.
+ // In IBM JRE, ClassLoader.getResources() does not call parent.getResources(); instead it
+ // recurssively calls findResources() for all parents in the delegation hierarchy.
+ // See issue #16364 for details.
+ @Override
+ protected Enumeration<URL> findResources(String name) throws IOException {
+ if (!name.startsWith("java/")) {
+ List<Enumeration<URL>> enumerations = new ArrayList<Enumeration<URL>>();
+ Enumeration<URL> apiResources = apiModuleLoader.getResources(name);
+ if (apiResources.hasMoreElements()) {
+ enumerations.add(apiResources);
+ }
+
+ // now punch-ins for various cases that require special handling
+ if (name.equals(MAILCAP)) {
+ // punch in for META-INF/mailcap files. see issue #8426
+ for (Module m : mr.getModules()) {
+ if (!select(m)) continue; // We don't look in unresolved modules
+ if (m == APIModule) continue; // we have already looked up resources in apiModuleLoader
+ enumerations.add(m.getClassLoader().getResources(name));
+ }
+ } else if (name.startsWith(META_INF_SERVICES)) {
+ // punch in. find the service loader from any module
+ String serviceName = name.substring(META_INF_SERVICES.length());
+ List<URL> punchedInURLs = new ArrayList<URL>();
+ for (Module m : mr.getModules()) {
+ if (!select(m)) continue; // We don't look in modules that don't meet punch in criteria
+ if (m == APIModule) continue; // we have already looked up resources in apiModuleLoader
+ punchedInURLs.addAll(m.getMetadata().getDescriptors(serviceName));
+ }
+ if (!punchedInURLs.isEmpty()) {
+ enumerations.add(Collections.enumeration(punchedInURLs));
+ }
+ }
+
+ // now assemble the result and return
+ switch (enumerations.size()) {
+ case 0:
+ return EMPTY_URLS;
+ case 1:
+ return enumerations.get(0);
+ default:
+ return new CompositeEnumeration(enumerations);
+ }
+ }
+ return EMPTY_URLS;
+ }
+
+ @Override
+ public String toString() {
+ return "APIClassLoader";
+ }
+
+ /**
+ * Takes a class name as used in Class.forName and converts it to a resource name as used in
+ * ClassLoader.getResource
+ *
+ * @param className className to be converted
+ * @return equivalent resource name
+ */
+ private String convertToResourceName(String className) {
+ return className.replace('.', '/').concat(".class");
+ }
+
+ private synchronized boolean isBlackListed(String name) {
+ return blacklist.contains(name);
+ }
+
+ private synchronized void addToBlackList(String name) {
+ blacklist.add(name);
+ }
+
+ private synchronized void clearBlackList() {
+ blacklist.clear();
+ }
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/AppLibClassLoaderServiceImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/AppLibClassLoaderServiceImpl.java
new file mode 100644
index 0000000..8f625db
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/AppLibClassLoaderServiceImpl.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.api.DelegatingClassLoader;
+import org.glassfish.internal.api.ClassLoaderHierarchy;
+import javax.inject.Inject;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Singleton;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+import java.io.IOException;
+
+/**
+ * This class is responsible for constructing class loader that has visibility
+ * to deploy time libraries (--libraries and EXTENSION_LIST of MANIFEST.MF,
+ * provided the library is available in 'applibs' directory) for an application.
+ * It is different from CommonClassLoader in a sense that the libraries that are part of
+ * common class loader are shared by all applications, where as this class
+ * loader adds a scope to a library.
+ *
+ * @author Sanjeeb.Sahoo@Sun.COM
+ */
+@Service
+@Singleton
+public class AppLibClassLoaderServiceImpl {
+ /*
+ * TODO(Sahoo): Not Yet Properly Implemented, as we have to bring in
+ * all the changes from
+ * http://fisheye5.cenqua.com/browse/glassfish/appserv-core/src/java/com/sun/enterprise/loader/EJBClassPathUtils.java
+ * To be specific, we have to bring in createApplicationLibrariesClassLoader().
+ */
+
+ @Inject
+ ServiceLocator habitat;
+
+ @Inject
+ CommonClassLoaderServiceImpl commonCLS;
+
+ private Map<URI, DelegatingClassLoader.ClassFinder> classFinderRegistry =
+ new HashMap<URI, DelegatingClassLoader.ClassFinder>();
+
+ /**
+ * @see org.glassfish.internal.api.ClassLoaderHierarchy#getAppLibClassLoader(String, List<URI>)
+ */
+ public ClassLoader getAppLibClassLoader(String application, List<URI> libURIs)
+ throws MalformedURLException {
+
+ ClassLoaderHierarchy clh = habitat.getService(ClassLoaderHierarchy.class);
+ DelegatingClassLoader connectorCL = clh.getConnectorClassLoader(application);
+
+ if (libURIs == null || libURIs.isEmpty()) {
+ // Optimization: when there are no libraries, why create an empty
+ // class loader in the hierarchy? Instead return the parent.
+ return connectorCL;
+ }
+
+ final ClassLoader commonCL = commonCLS.getCommonClassLoader();
+ DelegatingClassLoader applibCL = AccessController.doPrivileged(new PrivilegedAction<DelegatingClassLoader>() {
+ public DelegatingClassLoader run() {
+ return new DelegatingClassLoader(commonCL);
+ }
+ });
+
+ // order of classfinders is important here :
+ // connector's classfinders should be added before libraries' classfinders
+ // as the delegation hierarchy is appCL->app-libsCL->connectorCL->commonCL->API-CL
+ // since we are merging connector and applib classfinders to be at same level,
+ // connector classfinders need to be be before applib classfinders in the horizontal
+ // search path
+ for (DelegatingClassLoader.ClassFinder cf : connectorCL.getDelegates()) {
+ applibCL.addDelegate(cf);
+ }
+ addDelegates(libURIs, applibCL);
+
+ return applibCL;
+ }
+
+ private void addDelegates(Collection<URI> libURIs, DelegatingClassLoader holder)
+ throws MalformedURLException {
+
+ ClassLoader commonCL = commonCLS.getCommonClassLoader();
+ for (URI libURI : libURIs) {
+ synchronized (this) {
+ DelegatingClassLoader.ClassFinder libCF = classFinderRegistry.get(libURI);
+ if (libCF == null) {
+ libCF = new URLClassFinder(new URL[]{libURI.toURL()}, commonCL);
+ classFinderRegistry.put(libURI, libCF);
+ }
+ holder.addDelegate(libCF);
+ }
+ }
+ }
+
+ /**
+ * @see org.glassfish.internal.api.ClassLoaderHierarchy#getAppLibClassFinder(List<URI>)
+ */
+ public DelegatingClassLoader.ClassFinder getAppLibClassFinder(Collection<URI> libURIs)
+ throws MalformedURLException {
+ final ClassLoader commonCL = commonCLS.getCommonClassLoader();
+ DelegatingClassLoader appLibClassFinder = AccessController.doPrivileged(new PrivilegedAction<DelegatingClassLoader>() {
+ public DelegatingClassLoader run() {
+ return new AppLibClassFinder(commonCL);
+ }
+ });
+ addDelegates(libURIs, appLibClassFinder);
+ return (DelegatingClassLoader.ClassFinder)appLibClassFinder;
+ }
+
+ private static class URLClassFinder extends URLClassLoader
+ implements DelegatingClassLoader.ClassFinder {
+
+ public URLClassFinder(URL[] urls, ClassLoader parent) {
+ super(urls, parent);
+ }
+
+ public Class<?> findClass(String name) throws ClassNotFoundException {
+ Class<?> c = this.findLoadedClass(name);
+ if (c!=null) {
+ return c;
+ }
+ return super.findClass(name);
+ }
+
+ public Class<?> findExistingClass(String name) {
+ return super.findLoadedClass(name);
+ }
+ }
+
+ private static class AppLibClassFinder extends DelegatingClassLoader implements DelegatingClassLoader.ClassFinder {
+
+ public AppLibClassFinder(ClassLoader parent, List<DelegatingClassLoader.ClassFinder> delegates)
+ throws IllegalArgumentException {
+ super(parent, delegates);
+ }
+
+ public AppLibClassFinder(ClassLoader parent) {
+ super(parent);
+ }
+
+ public Class<?> findExistingClass(String name) {
+ // no action needed as parent is delegating classloader which will never be a defining classloader
+ return null;
+ }
+
+ public URL findResource(String name) {
+ return super.findResource(name);
+ }
+
+ public Enumeration<URL> findResources(String name) throws IOException {
+ return super.findResources(name);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/AppServerStartup.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/AppServerStartup.java
new file mode 100644
index 0000000..7a5d07f
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/AppServerStartup.java
@@ -0,0 +1,712 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+
+import com.sun.appserv.server.util.Version;
+import com.sun.enterprise.module.Module;
+import com.sun.enterprise.module.ModuleState;
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.module.bootstrap.ModuleStartup;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.util.Result;
+import com.sun.enterprise.v3.common.DoNothingActionReporter;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import org.glassfish.api.FutureProvider;
+import org.glassfish.api.StartupRunLevel;
+import org.glassfish.api.admin.CommandRunner;
+import org.glassfish.api.admin.ParameterMap;
+import org.glassfish.api.admin.ProcessEnvironment;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.event.EventListener.Event;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.common.util.Constants;
+import org.glassfish.hk2.api.ActiveDescriptor;
+import org.glassfish.hk2.api.Descriptor;
+import org.glassfish.hk2.api.DynamicConfiguration;
+import org.glassfish.hk2.api.DynamicConfigurationService;
+import org.glassfish.hk2.api.Filter;
+import org.glassfish.hk2.api.InstanceLifecycleEvent;
+import org.glassfish.hk2.api.InstanceLifecycleEventType;
+import org.glassfish.hk2.api.InstanceLifecycleListener;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.Rank;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.runlevel.ChangeableRunLevelFuture;
+import org.glassfish.hk2.runlevel.ErrorInformation;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.hk2.runlevel.RunLevelController;
+import org.glassfish.hk2.runlevel.RunLevelFuture;
+import org.glassfish.hk2.runlevel.RunLevelListener;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.glassfish.internal.api.InitRunLevel;
+import org.glassfish.internal.api.InternalSystemAdministrator;
+import org.glassfish.internal.api.PostStartupRunLevel;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.glassfish.server.ServerEnvironmentImpl;
+import org.jvnet.hk2.annotations.Service;
+
+
+/**
+ * Main class for Glassfish startup
+ * This class spawns a non-daemon Thread when the start() is called.
+ * Having a non-daemon thread allows us to control lifecycle of server JVM.
+ * The thead is stopped when stop() is called.
+ *
+ * @author Jerome Dochez, sahoo@sun.com
+ */
+@Service
+@Rank(Constants.DEFAULT_IMPLEMENTATION_RANK) // This should be the default impl if no name is specified
+public class AppServerStartup implements PostConstruct, ModuleStartup {
+
+ StartupContext context;
+
+ final static Logger logger = KernelLoggerInfo.getLogger();
+
+ final static Level level = Level.FINE;
+
+ @Inject
+ ServerEnvironmentImpl env;
+
+ @Inject
+ ServiceLocator locator;
+
+ @Inject
+ ModulesRegistry systemRegistry;
+
+ @Inject
+ public void setStartupContext(StartupContext context) {
+ this.context = context;
+ }
+
+ @Inject
+ ExecutorService executor;
+
+ @Inject
+ Events events;
+
+ @Inject
+ CommonClassLoaderServiceImpl commonCLS;
+
+ @Inject
+ SystemTasks pidWriter;
+
+ @Inject
+ RunLevelController runLevelController;
+
+ @Inject
+ Provider<CommandRunner> commandRunnerProvider;
+
+ @Inject
+ private AppInstanceListener appInstanceListener;
+
+ private MasterRunLevelListener masterListener;
+
+ private long platformInitTime;
+
+ private String platform = System.getProperty("GlassFish_Platform");
+
+ /**
+ * A keep alive thread that keeps the server JVM from going down
+ * as long as GlassFish kernel is up.
+ */
+ private Thread serverThread;
+ private boolean shutdownSignal = false;
+
+ private final static String THREAD_POLICY_PROPERTY = "org.glassfish.startupThreadPolicy";
+ private final static String MAX_STARTUP_THREAD_PROPERTY = "org.glassfish.maxStartupThreads";
+
+ private final static String POLICY_FULLY_THREADED = "FULLY_THREADED";
+ private final static String POLICY_USE_NO_THREADS = "USE_NO_THREADS";
+
+ private final static int DEFAULT_STARTUP_THREADS = 4;
+ private final static String FELIX_PLATFORM = "Felix";
+ private final static String STATIC_PLATFORM = "Static";
+
+ @Override
+ public void postConstruct() {
+ masterListener = new MasterRunLevelListener(runLevelController);
+ String threadPolicy = System.getProperty(THREAD_POLICY_PROPERTY);
+ if (threadPolicy != null) {
+ if (POLICY_FULLY_THREADED.equals(threadPolicy)) {
+ logger.fine("Using startup thread policy FULLY_THREADED at behest of system property");
+ runLevelController.setThreadingPolicy(RunLevelController.ThreadingPolicy.FULLY_THREADED);
+ }
+ else if (POLICY_USE_NO_THREADS.equals(threadPolicy)) {
+ logger.fine("Using startup thread policy USE_NO_THREADS at behest of system property");
+ runLevelController.setThreadingPolicy(RunLevelController.ThreadingPolicy.USE_NO_THREADS);
+ }
+ else {
+ logger.warning("Unknown threading policy " + threadPolicy + ". Will use the current policy of " +
+ runLevelController.getThreadingPolicy());
+ }
+ }
+ else {
+ if (platform == null || !(platform.equals(FELIX_PLATFORM) || platform.equals(STATIC_PLATFORM))) {
+ runLevelController.setThreadingPolicy(RunLevelController.ThreadingPolicy.USE_NO_THREADS);
+ }
+ }
+
+ int numThreads = Integer.getInteger(MAX_STARTUP_THREAD_PROPERTY, DEFAULT_STARTUP_THREADS);
+ if (numThreads > 0) {
+ logger.fine("Startup controller will use " + numThreads + " + threads");
+ runLevelController.setMaximumUseableThreads(numThreads);
+ }
+ else {
+ logger.fine("Startup controller will use infinite threads");
+ }
+
+ }
+
+ public synchronized void start() {
+ ClassLoader origCL = Thread.currentThread().getContextClassLoader();
+ try {
+ // See issue #5596 to know why we set context CL as common CL.
+ Thread.currentThread().setContextClassLoader(
+ commonCLS.getCommonClassLoader());
+ doStart();
+ } finally {
+ // reset the context classloader. See issue GLASSFISH-15775
+ Thread.currentThread().setContextClassLoader(origCL);
+ }
+ }
+
+ private void doStart() {
+
+ run();
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ // spwan a non-daemon thread that waits indefinitely for shutdown request.
+ // This stops the VM process from exiting.
+ serverThread = new Thread("GlassFish Kernel Main Thread"){
+ @Override
+ public void run() {
+ logger.logp(level, "AppServerStartup", "run",
+ "[{0}] started", new Object[]{this});
+
+ // notify the other thread to continue now that a non-daemon
+ // thread has started.
+ latch.countDown();
+
+ synchronized (this) {
+ while (!shutdownSignal) {
+ try {
+ wait(); // Wait indefinitely until shutdown is requested
+ }
+ catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ logger.logp(level, "AppServerStartup", "run",
+ "[{0}] exiting", new Object[]{this});
+ }
+ };
+
+ // by default a thread inherits daemon status of parent thread.
+ // Since this method can be called by non-daemon threads (e.g.,
+ // PackageAdmin service in case of an update of bundles), we
+ // have to explicitly set the daemon status to false.
+ serverThread.setDaemon(false);
+ serverThread.start();
+
+ // wait until we have spawned a non-daemon thread
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void run() {
+
+ if (context==null) {
+ System.err.println("Startup context not provided, cannot continue");
+ return;
+ }
+
+ if (platform==null) {
+ platform = "Embedded";
+ }
+
+ platformInitTime = System.currentTimeMillis();
+
+ if (logger.isLoggable(level)) {
+ logger.log(level, "Startup class : {0}", getClass().getName());
+ }
+
+ // prepare the global variables
+ DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
+ DynamicConfiguration config = dcs.createDynamicConfiguration();
+
+ config.addActiveDescriptor(BuilderHelper.createConstantDescriptor(logger));
+ config.addActiveDescriptor(BuilderHelper.createConstantDescriptor(masterListener));
+
+ config.addUnbindFilter(BuilderHelper.createContractFilter(ProcessEnvironment.class.getName()));
+
+ config.addActiveDescriptor(BuilderHelper.createConstantDescriptor(
+ env.isEmbedded() ?
+ new ProcessEnvironment(ProcessEnvironment.ProcessType.Embedded):
+ new ProcessEnvironment(ProcessEnvironment.ProcessType.Server)));
+ config.commit();
+
+
+
+ // activate the run level services
+ masterListener.reset();
+
+ long initFinishTime = 0L;
+ long startupFinishTime = 0L;
+
+ if (!proceedTo(InitRunLevel.VAL)) {
+ appInstanceListener.stopRecordingTimes();
+ return;
+ }
+
+ if (!logger.isLoggable(level)) {
+ // Stop recording the times, no-one cares
+ appInstanceListener.stopRecordingTimes();
+ }
+ else {
+ initFinishTime = System.currentTimeMillis();
+ logger.log(level, "Init level done in " +
+ (initFinishTime - context.getCreationTime()) + " ms");
+ }
+
+ appInstanceListener.startRecordingFutures();
+ if (!proceedTo(StartupRunLevel.VAL)) {
+ appInstanceListener.stopRecordingTimes();
+ return;
+ }
+
+ if (!postStartupJob()) {
+ appInstanceListener.stopRecordingTimes();
+ return;
+ }
+
+ if (logger.isLoggable(level)) {
+
+ startupFinishTime = System.currentTimeMillis();
+ logger.log(level, "Startup level done in " +
+ (startupFinishTime - initFinishTime) + " ms");
+ }
+
+ if (!proceedTo(PostStartupRunLevel.VAL)) {
+ appInstanceListener.stopRecordingTimes();
+ return;
+ }
+
+ if (logger.isLoggable(level)) {
+
+ long postStartupFinishTime = System.currentTimeMillis();
+ logger.log(level, "PostStartup level done in " +
+ (postStartupFinishTime - startupFinishTime) + " ms");
+ }
+ }
+
+ private boolean postStartupJob() {
+ LinkedList<Future<Result<Thread>>> futures = appInstanceListener.getFutures();
+
+ env.setStatus(ServerEnvironment.Status.starting);
+ events.send(new Event(EventTypes.SERVER_STARTUP), false);
+
+ // finally let's calculate our starting times
+ long nowTime = System.currentTimeMillis();
+ logger.log(Level.INFO, KernelLoggerInfo.startupEndMessage,
+ new Object[] { Version.getVersion(), Version.getBuildVersion(), platform,
+ (platformInitTime - context.getCreationTime()),
+ (nowTime - platformInitTime),
+ nowTime - context.getCreationTime()});
+
+ printModuleStatus(systemRegistry, level);
+
+ String wallClockStart = System.getProperty("WALL_CLOCK_START");
+ if (wallClockStart != null) {
+ try {
+ // it will only be set when called from AsadminMain and the env. variable AS_DEBUG is set to true
+ long realstart = Long.parseLong(wallClockStart);
+ logger.log(Level.INFO, KernelLoggerInfo.startupTotalTime, (System.currentTimeMillis() - realstart));
+ }
+ catch(Exception e) {
+ // do nothing.
+ }
+ }
+
+ for (Future<Result<Thread>> future : futures) {
+ try {
+ try {
+ // wait for an eventual status, otherwise ignore
+ if (future.get(3, TimeUnit.SECONDS).isFailure()) {
+ final Throwable t = future.get().exception();
+ logger.log(Level.SEVERE, KernelLoggerInfo.startupFatalException, t);
+ events.send(new Event(EventTypes.SERVER_SHUTDOWN), false);
+ shutdown();
+ return false;
+ }
+ } catch(TimeoutException e) {
+ logger.log(Level.WARNING, KernelLoggerInfo.startupWaitTimeout, e);
+ }
+ } catch(Throwable t) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.startupException, t);
+ }
+ }
+
+ env.setStatus(ServerEnvironment.Status.started);
+ events.send(new Event(EventTypes.SERVER_READY), false);
+ pidWriter.writePidFile();
+
+ return true;
+ }
+
+ public static void printModuleStatus(ModulesRegistry registry, Level level) {
+
+ if (!logger.isLoggable(level) || registry == null) {
+ return;
+ }
+
+ StringBuilder sb = new StringBuilder("Module Status Report Begins\n");
+ // first started :
+
+ for (Module m : registry.getModules()) {
+ if (m.getState()== ModuleState.READY) {
+ sb.append(m).append("\n");
+ }
+ }
+ sb.append("\n");
+ // then resolved
+ for (Module m : registry.getModules()) {
+ if (m.getState()== ModuleState.RESOLVED) {
+ sb.append(m).append("\n");
+ }
+ }
+ sb.append("\n");
+ // finally installed
+ for (Module m : registry.getModules()) {
+ if (m.getState()!= ModuleState.READY && m.getState()!=ModuleState.RESOLVED) {
+ sb.append(m).append("\n");
+ }
+ }
+ sb.append("Module Status Report Ends");
+ logger.log(level, sb.toString());
+ }
+
+ // TODO(Sahoo): Revisit this method after discussing with Jerome.
+ private void shutdown() {
+ CommandRunner runner = commandRunnerProvider.get();
+
+ if (runner!=null) {
+ final ParameterMap params = new ParameterMap();
+ // By default we don't want to shutdown forcefully, as that will cause the VM to exit and that's not
+ // a very good behavior for a code known to be embedded in other processes.
+ final boolean noForcedShutdown =
+ Boolean.parseBoolean(context.getArguments().getProperty(
+ com.sun.enterprise.glassfish.bootstrap.Constants.NO_FORCED_SHUTDOWN, "true"));
+ if (noForcedShutdown) {
+ params.set("force", "false");
+ }
+ final InternalSystemAdministrator kernelIdentity = locator.getService(InternalSystemAdministrator.class);
+ if (env.isDas()) {
+ runner.getCommandInvocation("stop-domain", new DoNothingActionReporter(), kernelIdentity.getSubject()).parameters(params).execute();
+ } else {
+ runner.getCommandInvocation("_stop-instance", new DoNothingActionReporter(), kernelIdentity.getSubject()).parameters(params).execute();
+ }
+ }
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public synchronized void stop() {
+ if(env.getStatus() == ServerEnvironment.Status.stopped) {
+ // During shutdown because of shutdown hooks, we can be stopped multiple times.
+ // In such a case, ignore any subsequent stop operations.
+ logger.fine("Already stopped, so just returning");
+ return;
+ }
+ env.setStatus(ServerEnvironment.Status.stopping);
+ try {
+ events.send(new Event(EventTypes.PREPARE_SHUTDOWN), false);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionDuringShutdown, e);
+ }
+
+ // deactivate the run level services
+ try {
+ proceedTo(InitRunLevel.VAL);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionDuringShutdown, e);
+ }
+
+ // first send the shutdown event synchronously
+ env.setStatus(ServerEnvironment.Status.stopped);
+ try {
+ events.send(new Event(EventTypes.SERVER_SHUTDOWN), false);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionDuringShutdown, e);
+ }
+
+ try {
+ runLevelController.proceedTo(0);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionDuringShutdown, e);
+ }
+
+ logger.info(KernelLoggerInfo.shutdownFinished);
+
+ // notify the server thread that we are done, so that it can come out.
+ if (serverThread!=null) {
+ synchronized (serverThread) {
+ shutdownSignal = true;
+
+ serverThread.notify();
+ }
+ try {
+ serverThread.join(0);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Proceed to the given run level using the given {@link AppServerActivator}.
+ *
+ * @param runLevel the run level to proceed to
+ * @param activator an {@link AppServerActivator activator} used to
+ * activate/deactivate the services
+ * @return false if an error occurred that required server shutdown; true otherwise
+ */
+ private boolean proceedTo(int runLevel) {
+
+ try {
+ runLevelController.proceedTo(runLevel);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.shutdownRequired, e);
+ shutdown();
+ return false;
+ }
+
+ return !masterListener.isForcedShutdown();
+ }
+
+ @Service
+ public static class AppInstanceListener implements InstanceLifecycleListener {
+ private static final Filter FILTER = new Filter() {
+
+ @Override
+ public boolean matches(Descriptor d) {
+ if (d.getScope() != null && d.getScope().equals(RunLevel.class.getName())) return true;
+
+ return false;
+ }
+
+ };
+
+ @Inject
+ private Provider<RunLevelController> controllerProvider;
+
+ private volatile RunLevelController controller;
+
+ private Map<String, Long> startTimes = new HashMap<String, Long>();
+ private LinkedHashMap<String, Long> recordedTimes = new LinkedHashMap<String, Long>();
+ private LinkedList<Future<Result<Thread>>> futures = null;
+
+ @Override
+ public Filter getFilter() {
+ return FILTER;
+ }
+
+ @Override
+ public void lifecycleEvent(InstanceLifecycleEvent lifecycleEvent) {
+ if (InstanceLifecycleEventType.PRE_PRODUCTION.equals(lifecycleEvent.getEventType())) {
+ doPreProduction(lifecycleEvent.getActiveDescriptor());
+ return;
+ }
+
+ if (InstanceLifecycleEventType.POST_PRODUCTION.equals(lifecycleEvent.getEventType())) {
+ doPostProduction(lifecycleEvent);
+ return;
+ }
+
+ if (InstanceLifecycleEventType.PRE_DESTRUCTION.equals(lifecycleEvent.getEventType())) {
+ doPreDestruction(lifecycleEvent.getActiveDescriptor());
+ return;
+ }
+
+ // All other events ignored
+ }
+
+ private RunLevelController getController() {
+ if (controller != null) return controller;
+
+ synchronized (this) {
+ if (controller != null) return controller;
+
+ controller = controllerProvider.get();
+ return controller;
+ }
+ }
+
+ private void stopRecordingTimes() {
+ startTimes = null;
+ recordedTimes = null;
+ }
+
+ private void startRecordingFutures() {
+ futures = new LinkedList<Future<Result<Thread>>>();
+ }
+
+ private LinkedList<Future<Result<Thread>>> getFutures() {
+ LinkedList<Future<Result<Thread>>> retVal = futures;
+ futures = null;
+ return retVal;
+ }
+
+ private void doPreProduction(ActiveDescriptor<?> descriptor) {
+ if (startTimes != null) {
+ startTimes.put(descriptor.getImplementation(), System.currentTimeMillis());
+ }
+
+ if ((getController().getCurrentRunLevel() > InitRunLevel.VAL) && logger.isLoggable(level)) {
+ logger.log(level, "Running service " + descriptor.getImplementation());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void doPostProduction(InstanceLifecycleEvent event) {
+ ActiveDescriptor<?> descriptor = event.getActiveDescriptor();
+
+ if (startTimes != null && recordedTimes != null) {
+
+ Long startupTime = startTimes.remove(descriptor.getImplementation());
+ if (startupTime == null) return;
+
+ recordedTimes.put(descriptor.getImplementation(),
+ (System.currentTimeMillis() - startupTime));
+ }
+
+ if ((getController().getCurrentRunLevel() > InitRunLevel.VAL) && logger.isLoggable(level)) {
+ logger.log(level, "Service " + descriptor.getImplementation() + " finished " +
+ event.getLifecycleObject());
+ }
+
+ if (futures != null) {
+ Object startup = event.getLifecycleObject();
+ if (startup instanceof FutureProvider) {
+ FutureProvider<Result<Thread>> futureProvider = (FutureProvider<Result<Thread>>) startup;
+
+ futures.addAll(futureProvider.getFutures());
+ }
+ }
+ }
+
+ private void doPreDestruction(ActiveDescriptor<?> descriptor) {
+ if (logger.isLoggable(level)) {
+ logger.log(level, "Releasing service {0}", descriptor.getImplementation());
+ }
+ }
+
+ private LinkedHashMap<String, Long> getAllRecordedTimes() {
+ LinkedHashMap<String, Long> retVal = recordedTimes;
+
+ stopRecordingTimes(); // Do not hold onto data that will never be needed again
+
+ return retVal;
+ }
+
+ }
+
+ @Singleton
+ private class MasterRunLevelListener implements RunLevelListener {
+ private final RunLevelController controller;
+
+ private boolean forcedShutdown = false;
+
+ private MasterRunLevelListener(RunLevelController controller) {
+ this.controller = controller;
+ }
+
+ private void reset() {
+ forcedShutdown = false;
+ }
+
+ private boolean isForcedShutdown() { return forcedShutdown; }
+
+ @Override
+ public void onCancelled(RunLevelFuture future,
+ int previousProceedTo) {
+ logger.log(Level.INFO, KernelLoggerInfo.shutdownRequested);
+
+ if (future.isDown()) return;
+
+ forcedShutdown = true;
+ shutdown();
+ }
+
+ @Override
+ public void onError(RunLevelFuture future, ErrorInformation info) {
+ if (future.isDown()) {
+ // TODO: Need a log message
+ logger.log(Level.WARNING, "An error occured when the system was coming down", info.getError());
+ return;
+ }
+
+ logger.log(Level.INFO, KernelLoggerInfo.shutdownRequested, info.getError());
+
+ if (controller.getCurrentRunLevel() >= InitRunLevel.VAL) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.startupFailure, info.getError());
+ events.send(new Event(EventTypes.SERVER_SHUTDOWN), false);
+ }
+
+ forcedShutdown = true;
+ shutdown();
+ }
+
+ @Override
+ public void onProgress(ChangeableRunLevelFuture future, int achievedLevel) {
+ if (achievedLevel == PostStartupRunLevel.VAL) {
+ if (logger.isLoggable(level)) {
+ printModuleStatus(systemRegistry, level);
+
+ LinkedHashMap<String, Long> recordedTimes = appInstanceListener.getAllRecordedTimes();
+
+ int lcv = 0;
+ if (recordedTimes != null) {
+ for (Map.Entry<String, Long> service : recordedTimes.entrySet()) {
+ logger.log(level, "Service(" + lcv++ +") : " + service.getKey() + " took " + service.getValue() + " ms");
+ }
+ }
+ }
+ }
+ }
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationConfigListener.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationConfigListener.java
new file mode 100644
index 0000000..42e3d89
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationConfigListener.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.config.serverbeans.Application;
+import com.sun.enterprise.config.serverbeans.ApplicationRef;
+import com.sun.enterprise.config.serverbeans.Applications;
+import com.sun.enterprise.config.serverbeans.Cluster;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.Server;
+import com.sun.enterprise.config.serverbeans.ServerTags;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.v3.common.HTMLActionReporter;
+import java.beans.PropertyChangeEvent;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.deployment.UndeployCommandParameters;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.internal.api.PostStartupRunLevel;
+import org.glassfish.internal.data.ApplicationInfo;
+import org.glassfish.internal.data.ApplicationRegistry;
+import org.glassfish.internal.deployment.Deployment;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.TransactionListener;
+import org.jvnet.hk2.config.Transactions;
+import org.jvnet.hk2.config.UnprocessedChangeEvents;
+
+@Service
+@RunLevel(PostStartupRunLevel.VAL)
+public class ApplicationConfigListener implements TransactionListener, PostConstruct {
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ApplicationConfigListener.class);
+
+ final private Logger logger = KernelLoggerInfo.getLogger();
+
+ @Inject
+ Transactions transactions;
+
+ @Inject
+ Domain domain;
+
+ @Inject
+ Applications applications;
+
+ @Inject
+ ApplicationRegistry appRegistry;
+
+ @Inject
+ Deployment deployment;
+
+ @Inject
+ StartupContext startupContext;
+
+ @Inject @Named( ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Server server;
+
+ private final static String UPGRADE_PARAM = "-upgrade";
+
+ public void transactionCommited( final List<PropertyChangeEvent> changes) {
+ boolean isUpdatingAttribute = true;
+ for (PropertyChangeEvent event : changes) {
+ Object oldValue = event.getOldValue();
+ Object newValue = event.getNewValue();
+ if (event.getSource() instanceof Applications) {
+ if (event.getPropertyName().equals(ServerTags.APPLICATION)) {
+ if (oldValue == null || newValue == null) {
+ // we are adding/removing application element here
+ // and updating existing attribute
+ isUpdatingAttribute = false;
+ break;
+ }
+ }
+ } else if (event.getSource() instanceof Server ||
+ event.getSource() instanceof Cluster) {
+ if (event.getPropertyName().equals(
+ ServerTags.APPLICATION_REF)) {
+ if (oldValue == null || newValue == null) {
+ // we are adding/removing application-ref element here
+ // and updating existing attribute
+ isUpdatingAttribute = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!isUpdatingAttribute) {
+ // if we are not updating existing attribute, we should
+ // skip the config listener
+ return;
+ }
+
+ for (PropertyChangeEvent event : changes) {
+ if (event.getSource() instanceof Application ||
+ event.getSource() instanceof ApplicationRef) {
+ Object oldValue = event.getOldValue();
+ Object newValue = event.getNewValue();
+ if (oldValue != null && newValue != null &&
+ oldValue instanceof String &&
+ newValue instanceof String &&
+ !((String)oldValue).equals((String)newValue)) {
+ // if it's an attribute change of the application
+ // element or application-ref element
+ Object parent = event.getSource();
+ String appName = null;
+ if (parent instanceof Application) {
+ appName = ((Application)parent).getName();
+ } else if (parent instanceof ApplicationRef) {
+ appName = ((ApplicationRef)parent).getRef();
+ }
+ // if it's not a user application, let's not do
+ // anything
+ if (applications.getApplication(appName) == null) {
+ return;
+ }
+ if (event.getPropertyName().equals(ServerTags.ENABLED)) {
+ // enable or disable application accordingly
+ handleAppEnableChange(event.getSource(),
+ appName, Boolean.valueOf((String)newValue));
+ } else if (event.getPropertyName().equals(ServerTags.CONTEXT_ROOT) || event.getPropertyName().equals(ServerTags.VIRTUAL_SERVERS) || event.getPropertyName().equals(ServerTags.AVAILABILITY_ENABLED)) {
+ // for other changes, reload the application
+ handleOtherAppConfigChanges(event.getSource(),
+ appName);
+ }
+ }
+ }
+ }
+ }
+
+ public void unprocessedTransactedEvents(
+ List<UnprocessedChangeEvents> changes) {
+ }
+
+ public void postConstruct() {
+ Properties arguments = startupContext.getArguments();
+ if (arguments != null) {
+ boolean isUpgrade = Boolean.valueOf(
+ arguments.getProperty(UPGRADE_PARAM));
+ if (isUpgrade) {
+ // we don't want to register this listener for the upgrade
+ // start up
+ return;
+ }
+ }
+ transactions.addTransactionsListener(this);
+ }
+
+ private void handleAppEnableChange(Object parent,
+ String appName, boolean enabled) {
+ Application application = applications.getApplication(appName);
+ if (application.isLifecycleModule()) {
+ return;
+ }
+ if (enabled) {
+ if (isCurrentInstanceMatchingTarget(parent)) {
+ enableApplication(appName);
+ }
+ } else {
+ if (isCurrentInstanceMatchingTarget(parent)) {
+ disableApplication(appName);
+ }
+ }
+ }
+
+ private void handleOtherAppConfigChanges(Object parent, String appName) {
+ Application application = applications.getApplication(appName);
+ if (application.isLifecycleModule()) {
+ return;
+ }
+ // reload the application for other application related
+ // config changes if the application is in enabled state
+ if (isCurrentInstanceMatchingTarget(parent) &&
+ deployment.isAppEnabled(application)) {
+ disableApplication(appName);
+ enableApplication(appName);
+ }
+ }
+
+
+ private boolean isCurrentInstanceMatchingTarget(Object parent) {
+ // DAS receive all the events, so we need to figure out
+ // whether we should take action on DAS depending on the event
+ if (parent instanceof ApplicationRef) {
+ Object grandparent = ((ApplicationRef)parent).getParent();
+ if (grandparent instanceof Server) {
+ Server gpServer = (Server)grandparent;
+ if ( ! server.getName().equals(gpServer.getName())) {
+ return false;
+ }
+ } else if (grandparent instanceof Cluster) {
+ if (server.isDas()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private void enableApplication(String appName) {
+ Application app = applications.getApplication(appName);
+ ApplicationRef appRef = domain.getApplicationRefInServer(server.getName(), appName);
+ // if the application does not exist or application is not referenced
+ // by the current server instance, do not load
+ if (app == null || appRef == null) {
+ return;
+ }
+
+ // if the application is not in enable state, do not load
+ if (!deployment.isAppEnabled(app)) {
+ return;
+ }
+
+ ApplicationInfo appInfo = appRegistry.get(appName);
+ if (appInfo == null || appInfo.isLoaded()) {
+ return;
+ }
+
+ long operationStartTime =
+ Calendar.getInstance().getTimeInMillis();
+
+ try {
+ ActionReport report = new HTMLActionReporter();
+
+ deployment.enable(server.getName(), app, appRef, report, logger);
+
+ if (report.getActionExitCode().equals(ActionReport.ExitCode.SUCCESS)) {
+ logger.log(Level.INFO, KernelLoggerInfo.loadingApplicationTime,
+ new Object[] { appName, (Calendar.getInstance().getTimeInMillis() - operationStartTime)});
+ } else if (report.getActionExitCode().equals(ActionReport.ExitCode.WARNING)){
+ logger.log(Level.WARNING, KernelLoggerInfo.loadingApplicationWarning,
+ new Object[] { appName, report.getMessage()});
+ } else if (report.getActionExitCode().equals(ActionReport.ExitCode.FAILURE)) {
+ throw new Exception(report.getMessage());
+ }
+ } catch(Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.loadingApplicationErrorEnable, e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void disableApplication(String appName) {
+ Application app = applications.getApplication(appName);
+ ApplicationRef appRef = domain.getApplicationRefInServer(server.getName(), appName);
+ // if the application does not exist or application is not referenced
+ // by the current server instance, do not unload
+ if (app == null || appRef == null) {
+ return;
+ }
+
+ ApplicationInfo appInfo = appRegistry.get(appName);
+ if (appInfo == null || !appInfo.isLoaded()) {
+ return;
+ }
+
+ try {
+ ActionReport report = new HTMLActionReporter();
+ UndeployCommandParameters commandParams =
+ new UndeployCommandParameters();
+ commandParams.name = appName;
+ commandParams.target = server.getName();
+ commandParams.origin = UndeployCommandParameters.Origin.unload;
+ commandParams.command = UndeployCommandParameters.Command.disable;
+ deployment.disable(commandParams, app, appInfo, report, logger);
+
+ if (report.getActionExitCode().equals(ActionReport.ExitCode.FAILURE)) {
+ throw new Exception(report.getMessage());
+ }
+ } catch(Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.loadingApplicationErrorDisable, e);
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java
new file mode 100644
index 0000000..fa04690
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java
@@ -0,0 +1,2247 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.config.serverbeans.*;
+import com.sun.enterprise.deploy.shared.ArchiveFactory;
+import com.sun.enterprise.deploy.shared.FileArchive;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import java.beans.PropertyVetoException;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.glassfish.api.*;
+import org.glassfish.api.admin.ParameterMap;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.admin.config.ApplicationName;
+import org.glassfish.api.container.Container;
+import org.glassfish.api.container.Sniffer;
+import org.glassfish.api.deployment.*;
+import org.glassfish.api.deployment.archive.*;
+import org.glassfish.api.event.*;
+import org.glassfish.api.event.EventListener.Event;
+import org.glassfish.api.virtualization.VirtualizationEnv;
+import org.glassfish.common.util.admin.ParameterMapExtractor;
+import org.glassfish.deployment.common.*;
+import org.glassfish.deployment.monitor.DeploymentLifecycleProbeProvider;
+import org.glassfish.deployment.versioning.VersioningSyntaxException;
+import org.glassfish.deployment.versioning.VersioningUtils;
+import org.glassfish.hk2.api.MultiException;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.PreDestroy;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.classmodel.reflect.Parser;
+import org.glassfish.hk2.classmodel.reflect.ParsingContext;
+import org.glassfish.hk2.classmodel.reflect.Types;
+import org.glassfish.internal.api.*;
+import org.glassfish.internal.data.*;
+import org.glassfish.internal.deployment.ApplicationLifecycleInterceptor;
+import org.glassfish.internal.deployment.Deployment;
+import org.glassfish.internal.deployment.DeploymentTracing;
+import org.glassfish.internal.deployment.ExtendedDeploymentContext;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.glassfish.server.ServerEnvironmentImpl;
+import org.jvnet.hk2.annotations.Optional;
+
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.ConfigBean;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.RetryableException;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.Transaction;
+import org.jvnet.hk2.config.TransactionFailure;
+import org.jvnet.hk2.config.types.Property;
+
+/**
+ * Application Loader is providing useful methods to load applications
+ *
+ * @author Jerome Dochez, Sanjeeb Sahoo
+ */
+@Service
+@Singleton
+public class ApplicationLifecycle implements Deployment, PostConstruct {
+
+ private static final String[] UPLOADED_GENERATED_DIRS = new String [] {"policy", "xml", "ejb", "jsp"};
+
+ @Inject
+ protected SnifferManagerImpl snifferManager;
+
+ @Inject
+ ServiceLocator habitat;
+
+ @Inject
+ ArchiveFactory archiveFactory;
+
+ @Inject
+ ContainerRegistry containerRegistry;
+
+ @Inject
+ public ApplicationRegistry appRegistry;
+
+ @Inject
+ protected Applications applications;
+
+ @Inject @Named( ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Server server;
+
+ @Inject
+ protected Domain domain;
+
+ @Inject
+ ServerEnvironmentImpl env;
+
+ @Inject @Optional
+ VirtualizationEnv virtEnv;
+
+ @Inject
+ Events events;
+
+ @Inject
+ ConfigSupport configSupport;
+
+ protected Logger logger = KernelLoggerInfo.getLogger();
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ApplicationLifecycle.class);
+
+ protected <T extends Container, U extends ApplicationContainer> Deployer<T, U> getDeployer(EngineInfo<T, U> engineInfo) {
+ return engineInfo.getDeployer();
+ }
+
+ protected DeploymentLifecycleProbeProvider
+ deploymentLifecycleProbeProvider = null;
+
+ private ExecutorService executorService = null;
+
+ private Collection<ApplicationLifecycleInterceptor> alcInterceptors = Collections.EMPTY_LIST;
+
+ public void postConstruct() {
+ executorService = createExecutorService();
+ deploymentLifecycleProbeProvider =
+ new DeploymentLifecycleProbeProvider();
+ alcInterceptors = habitat.getAllServices(
+ ApplicationLifecycleInterceptor.class);
+ }
+
+ /**
+ * Returns the ArchiveHandler for the passed archive abstraction or null
+ * if there are none.
+ *
+ * @param archive the archive to find the handler for
+ * @return the archive handler or null if not found.
+ * @throws IOException when an error occur
+ */
+ public ArchiveHandler getArchiveHandler(ReadableArchive archive) throws IOException {
+ return getArchiveHandler(archive, null);
+ }
+
+ /**
+ * Returns the ArchiveHandler for the passed archive abstraction or null
+ * if there are none.
+ *
+ * @param archive the archive to find the handler for
+ * @param type the type of the archive
+ * @return the archive handler or null if not found.
+ * @throws IOException when an error occur
+ */
+ public ArchiveHandler getArchiveHandler(ReadableArchive archive, String type) throws IOException {
+ if (type != null) {
+ return habitat.<ArchiveDetector>getService(ArchiveDetector.class, type).getArchiveHandler();
+ }
+ List<ArchiveDetector> detectors = new ArrayList<ArchiveDetector>(habitat.<ArchiveDetector>getAllServices(ArchiveDetector.class));
+ Collections.sort(detectors, new Comparator<ArchiveDetector>() {
+ // rank 2 is considered lower than rank 1, let's sort them in inceasing order
+ @Override
+ public int compare(ArchiveDetector o1, ArchiveDetector o2) {
+ return o1.rank() - o2.rank();
+ }
+ });
+ for (ArchiveDetector ad : detectors) {
+ if (ad.handles(archive)) {
+ return ad.getArchiveHandler();
+ }
+ }
+ return null;
+ }
+
+ public ApplicationInfo deploy(final ExtendedDeploymentContext context) {
+ return deploy(null, context);
+ }
+
+ public ApplicationInfo deploy(Collection<? extends Sniffer> sniffers, final ExtendedDeploymentContext context) {
+
+ long operationStartTime = Calendar.getInstance().getTimeInMillis();
+
+ events.send(new Event<DeploymentContext>(Deployment.DEPLOYMENT_START, context), false);
+ final ActionReport report = context.getActionReport();
+
+ final DeployCommandParameters commandParams = context.getCommandParameters(DeployCommandParameters.class);
+
+ final String appName = commandParams.name();
+ if (commandParams.origin == OpsParams.Origin.deploy &&
+ appRegistry.get(appName) != null) {
+ report.setMessage(localStrings.getLocalString("appnamenotunique","Application name {0} is already in use. Please pick a different name.", appName));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return null;
+ }
+
+ // if the virtualservers param is not defined, set it to all
+ // defined virtual servers minus __asadmin on that target
+ if (commandParams.virtualservers == null) {
+ commandParams.virtualservers = DeploymentUtils.getVirtualServers(
+ commandParams.target, env, domain);
+ }
+
+ if (commandParams.enabled == null) {
+ commandParams.enabled = Boolean.TRUE;
+ }
+
+ if (commandParams.altdd != null) {
+ context.getSource().addArchiveMetaData(DeploymentProperties.ALT_DD, commandParams.altdd);
+ }
+
+ if (commandParams.runtimealtdd != null) {
+ context.getSource().addArchiveMetaData(DeploymentProperties.RUNTIME_ALT_DD, commandParams.runtimealtdd);
+ }
+
+ ProgressTracker tracker = new ProgressTracker() {
+ @Override
+ public void actOn(Logger logger) {
+ //loaded is used instead of started to include more modules to
+ //stop. In some modules, the setup and cleanup steps are not
+ //fully symmetric, and to ensure thorough cleanup, we need to
+ //call module.stop() for started modules, and modules that are
+ //loaded but may not be started. Issue 18263
+ for (EngineRef module : get("loaded", EngineRef.class)) {
+ try {
+ module.stop(context);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ try {
+ PreDestroy.class.cast(context).preDestroy();
+ } catch (Exception e) {
+ // ignore
+ }
+ for (EngineRef module : get("loaded", EngineRef.class)) {
+ try {
+ module.unload(context);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ try {
+ ApplicationInfo appInfo = appRegistry.get(appName);
+ if (appInfo != null) {
+ // send the event to close necessary resources
+ events.send(new Event<ApplicationInfo>(Deployment.APPLICATION_DISABLED, appInfo));
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ for (EngineRef module : get("prepared", EngineRef.class)) {
+ try {
+ module.clean(context);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ // comment this out for now as the interceptor seems to use
+ // a different hook to roll back failure
+ // notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.REPLICATION, context);
+
+ if (!commandParams.keepfailedstubs) {
+ try {
+ context.clean();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ appRegistry.remove(appName);
+
+ }
+ };
+
+ context.addTransientAppMetaData(ExtendedDeploymentContext.TRACKER,
+ tracker);
+ context.setPhase(DeploymentContextImpl.Phase.PREPARE);
+ ApplicationInfo appInfo = null;
+ try {
+ ArchiveHandler handler = context.getArchiveHandler();
+ if (handler == null) {
+ handler = getArchiveHandler(context.getSource(),
+ commandParams.type);
+ context.setArchiveHandler(handler);
+ }
+
+ if (handler==null) {
+ report.setMessage(localStrings.getLocalString("unknownarchivetype","Archive type of {0} was not recognized",context.getSourceDir()));
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return null;
+ }
+
+ DeploymentTracing tracing = context.getModuleMetaData(DeploymentTracing.class);
+
+ if (tracing!=null) {
+ tracing.addMark(DeploymentTracing.Mark.ARCHIVE_HANDLER_OBTAINED);
+ }
+
+ if (handler.requiresAnnotationScanning(context.getSource())) {
+ getDeployableTypes(context);
+ }
+
+ if (tracing!=null) {
+ tracing.addMark(DeploymentTracing.Mark.PARSING_DONE);
+ }
+
+ // containers that are started are not stopped even if
+ // the deployment fail, the main reason
+ // is that some container do not support to be restarted.
+ if (sniffers!=null && logger.isLoggable(Level.FINE)) {
+ for (Sniffer sniffer : sniffers) {
+ logger.fine("Before Sorting" + sniffer.getModuleType());
+ }
+ }
+
+ sniffers = getSniffers(handler, sniffers, context);
+
+ ClassLoaderHierarchy clh = habitat.getService(ClassLoaderHierarchy.class);
+ if (tracing!=null) {
+ tracing.addMark(DeploymentTracing.Mark.CLASS_LOADER_HIERARCHY);
+ }
+
+ context.createDeploymentClassLoader(clh, handler);
+ events.send(new Event<DeploymentContext>(Deployment.AFTER_DEPLOYMENT_CLASSLOADER_CREATION, context), false);
+
+ if (tracing!=null) {
+ tracing.addMark(DeploymentTracing.Mark.CLASS_LOADER_CREATED);
+ }
+
+ final ClassLoader cloader = context.getClassLoader();
+ final ClassLoader currentCL = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(cloader);
+
+ List<EngineInfo> sortedEngineInfos =
+ setupContainerInfos(handler, sniffers, context);
+ if (tracing!=null) {
+ tracing.addMark(DeploymentTracing.Mark.CONTAINERS_SETUP_DONE);
+ }
+
+ if (logger.isLoggable(Level.FINE)) {
+ for (EngineInfo info : sortedEngineInfos) {
+ logger.fine("After Sorting " + info.getSniffer().getModuleType());
+ }
+ }
+ if (sortedEngineInfos ==null || sortedEngineInfos.isEmpty()) {
+ report.failure(logger, localStrings.getLocalString("unknowncontainertype","There is no installed container capable of handling this application {0}",context.getSource().getName()));
+ tracker.actOn(logger);
+ return null;
+ }
+
+
+ // create a temporary application info to hold metadata
+ // so the metadata could be accessed at classloader
+ // construction time through ApplicationInfo
+ ApplicationInfo tempAppInfo = new ApplicationInfo(events,
+ context.getSource(), appName);
+ for (Object m : context.getModuleMetadata()) {
+ tempAppInfo.addMetaData(m);
+ }
+ tempAppInfo.setIsJavaEEApp(sortedEngineInfos);
+ // set the flag on the archive to indicate whether it's
+ // a JavaEE archive or not
+ context.getSource().setExtraData(Boolean.class, tempAppInfo.isJavaEEApp());
+ appRegistry.add(appName, tempAppInfo);
+
+ try {
+ notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.PREPARE, context);
+ } catch(Throwable interceptorException) {
+ report.failure(logger, "Exception while invoking the lifecycle interceptor", null);
+ report.setFailureCause(interceptorException);
+ logger.log(Level.SEVERE, KernelLoggerInfo.lifecycleException, interceptorException);
+ tracker.actOn(logger);
+ return null;
+ }
+
+ events.send(new Event<DeploymentContext>(Deployment.DEPLOYMENT_BEFORE_CLASSLOADER_CREATION, context), false);
+
+ context.createApplicationClassLoader(clh, handler);
+
+ events.send(new Event<DeploymentContext>(Deployment.AFTER_APPLICATION_CLASSLOADER_CREATION, context), false);
+
+ if (tracing!=null) {
+ tracing.addMark(DeploymentTracing.Mark.CLASS_LOADER_CREATED);
+ }
+
+ // this is a first time deployment as opposed as load following an unload event,
+ // we need to create the application info
+ // todo : we should come up with a general Composite API solution
+ ModuleInfo moduleInfo = null;
+ try {
+ moduleInfo = prepareModule(sortedEngineInfos, appName, context, tracker);
+ // Now that the prepare phase is done, any artifacts
+ // should be available. Go ahead and create the
+ // downloadable client JAR. We want to do this now, or
+ // at least before the load and start phases, because
+ // (for example) the app client deployer start phase
+ // needs to find all generated files when it runs.
+ final ClientJarWriter cjw = new ClientJarWriter(context);
+ cjw.run();
+ } catch(Throwable prepareException) {
+ prepareException.printStackTrace();
+ report.failure(logger, "Exception while preparing the app", null);
+ report.setFailureCause(prepareException);
+ logger.log(Level.SEVERE, KernelLoggerInfo.lifecycleException, prepareException);
+ tracker.actOn(logger);
+ return null;
+ }
+
+ // the deployer did not take care of populating the application info, this
+ // is not a composite module.
+ appInfo=context.getModuleMetaData(ApplicationInfo.class);
+ if (appInfo==null) {
+ appInfo = new ApplicationInfo(events, context.getSource(), appName);
+ appInfo.addModule(moduleInfo);
+
+ for (Object m : context.getModuleMetadata()) {
+ moduleInfo.addMetaData(m);
+ appInfo.addMetaData(m);
+ }
+ } else {
+ for (EngineRef ref : moduleInfo.getEngineRefs()) {
+ appInfo.add(ref);
+ }
+ }
+
+ // remove the temp application info from the registry
+ // first, then register the real one
+ appRegistry.remove(appName);
+ appInfo.setIsJavaEEApp(sortedEngineInfos);
+ appRegistry.add(appName, appInfo);
+
+ notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.PREPARE, context);
+
+ if (tracing!=null) {
+ tracing.addMark(DeploymentTracing.Mark.PREPARED);
+ }
+
+ // send the APPLICATION_PREPARED event
+ // set the phase and thread context classloader properly
+ // before sending the event
+ context.setPhase(DeploymentContextImpl.Phase.PREPARED);
+ Thread.currentThread().setContextClassLoader(context.getClassLoader());
+ appInfo.setAppClassLoader(context.getClassLoader());
+ events.send(new Event<DeploymentContext>(Deployment.APPLICATION_PREPARED, context), false);
+
+ // now were falling back into the mainstream loading/starting sequence, at this
+ // time the containers are set up, all the modules have been prepared in their
+ // associated engines and the application info is created and registered
+ if (loadOnCurrentInstance(context)) {
+ appInfo.setLibraries(commandParams.libraries());
+ try {
+ notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.LOAD, context);
+ appInfo.load(context, tracker);
+ notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.LOAD, context);
+
+ notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.START, context);
+ appInfo.start(context, tracker);
+ notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.START, context);
+ } catch(Throwable loadException) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.lifecycleException, loadException);
+ report.failure(logger, "Exception while loading the app", null);
+ report.setFailureCause(loadException);
+ tracker.actOn(logger);
+ return null;
+ }
+ }
+ return appInfo;
+ } finally {
+ context.postDeployClean(false /* not final clean-up yet */);
+ Thread.currentThread().setContextClassLoader(currentCL);
+ }
+
+ } catch (Throwable e) {
+ report.failure(logger, localStrings.getLocalString("error.deploying.app", "Exception while deploying the app [{0}]", appName), null);
+ report.setFailureCause(e);
+ logger.log(Level.SEVERE, KernelLoggerInfo.lifecycleException, e);
+ tracker.actOn(logger);
+ return null;
+ } finally {
+ if (report.getActionExitCode()==ActionReport.ExitCode.SUCCESS) {
+ events.send(new Event<ApplicationInfo>(Deployment.DEPLOYMENT_SUCCESS, appInfo));
+ long operationTime = Calendar.getInstance().getTimeInMillis() - operationStartTime;
+ if (appInfo != null) {
+ deploymentLifecycleProbeProvider.applicationDeployedEvent(appName, getApplicationType(appInfo), String.valueOf(operationTime));
+ }
+ } else {
+ events.send(new Event<DeploymentContext>(Deployment.DEPLOYMENT_FAILURE, context));
+ }
+ }
+ }
+
+ @Override
+ public Types getDeployableTypes(DeploymentContext context) throws IOException {
+
+ synchronized(context) {
+ Types types = context.getTransientAppMetaData(Types.class.getName(), Types.class);
+ if (types!=null) {
+ return types;
+ } else {
+
+ try {
+ // scan the jar and store the result in the deployment context.
+ ParsingContext parsingContext = new ParsingContext.Builder().logger(context.getLogger()).executorService(executorService).build();
+ Parser parser = new Parser(parsingContext);
+ ReadableArchiveScannerAdapter scannerAdapter = new ReadableArchiveScannerAdapter(parser, context.getSource());
+ parser.parse(scannerAdapter, null);
+ for (ReadableArchive externalLibArchive :
+ getExternalLibraries(context)) {
+ ReadableArchiveScannerAdapter libAdapter = null;
+ try {
+ libAdapter = new ReadableArchiveScannerAdapter(parser, externalLibArchive);
+ parser.parse(libAdapter, null);
+ } finally {
+ if (libAdapter!=null) {
+ libAdapter.close();
+ }
+ }
+ }
+ parser.awaitTermination();
+ scannerAdapter.close();
+ context.addTransientAppMetaData(Types.class.getName(), parsingContext.getTypes());
+ context.addTransientAppMetaData(Parser.class.getName(), parser);
+ return parsingContext.getTypes();
+ } catch(InterruptedException e) {
+ throw new IOException(e);
+ }
+ }
+ }
+ }
+
+ private void notifyLifecycleInterceptorsBefore(final ExtendedDeploymentContext.Phase phase,
+ final ExtendedDeploymentContext dc) {
+ for (ApplicationLifecycleInterceptor i : alcInterceptors) {
+ i.before(phase, dc);
+ }
+ }
+
+ private void notifyLifecycleInterceptorsAfter(final ExtendedDeploymentContext.Phase phase,
+ final ExtendedDeploymentContext dc) {
+ for (ApplicationLifecycleInterceptor i : alcInterceptors) {
+ i.after(phase, dc);
+ }
+ }
+
+ private List<ReadableArchive> getExternalLibraries(
+ DeploymentContext context) throws IOException {
+ List<ReadableArchive> externalLibArchives = new ArrayList<ReadableArchive>();
+
+ String skipScanExternalLibProp = context.getAppProps().getProperty(
+ DeploymentProperties.SKIP_SCAN_EXTERNAL_LIB);
+
+ if (Boolean.valueOf(skipScanExternalLibProp)) {
+ // if we skip scanning external libraries, we should just
+ // return an empty list here
+ return Collections.EMPTY_LIST;
+ }
+
+ List<URI> externalLibs = DeploymentUtils.getExternalLibraries(context.getSource());
+ for (URI externalLib : externalLibs) {
+ externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath())));
+ }
+
+ return externalLibArchives;
+ }
+
+ /**
+ * Suspends this application.
+ *
+ * @param appName the registration application ID
+ * @return true if suspending was successful, false otherwise.
+ */
+ public boolean suspend(String appName) {
+ boolean isSuccess = true;
+
+ ApplicationInfo appInfo = appRegistry.get(appName);
+ if (appInfo != null) {
+ isSuccess = appInfo.suspend(logger);
+ }
+
+ return isSuccess;
+ }
+
+ /**
+ * Resumes this application.
+ *
+ * @param appName the registration application ID
+ * @return true if resumption was successful, false otherwise.
+ */
+ public boolean resume(String appName) {
+ boolean isSuccess = true;
+
+ ApplicationInfo appInfo = appRegistry.get(appName);
+ if (appInfo != null) {
+ isSuccess = appInfo.resume(logger);
+ }
+
+ return isSuccess;
+ }
+
+ public List<EngineInfo> setupContainerInfos(DeploymentContext context)
+ throws Exception {
+ return setupContainerInfos(context.getArchiveHandler(), getSniffers(context.getArchiveHandler(), null, context), context);
+ }
+
+ public Collection<? extends Sniffer> getSniffers(final ArchiveHandler handler, Collection<? extends Sniffer> sniffers, DeploymentContext context) {
+ if (handler == null) {
+ return Collections.EMPTY_LIST;
+ }
+
+ if (sniffers==null) {
+ if (handler instanceof CompositeHandler) {
+ ((CompositeHandler)handler).initCompositeMetaData(context);
+ context.getAppProps().setProperty(ServerTags.IS_COMPOSITE, "true");
+ }
+ sniffers = snifferManager.getSniffers(context);
+ }
+ context.addTransientAppMetaData(DeploymentProperties.SNIFFERS, sniffers);
+ snifferManager.validateSniffers(sniffers, context);
+
+ return sniffers;
+ }
+
+ // set up containers and prepare the sorted ModuleInfos
+ public List<EngineInfo> setupContainerInfos(final ArchiveHandler handler,
+ Collection<? extends Sniffer> sniffers, DeploymentContext context)
+ throws Exception {
+
+ final ActionReport report = context.getActionReport();
+
+ DeploymentTracing tracing = context.getModuleMetaData(DeploymentTracing.class);
+
+ Map<Deployer, EngineInfo> containerInfosByDeployers = new LinkedHashMap<Deployer, EngineInfo>();
+
+ for (Sniffer sniffer : sniffers) {
+ if (sniffer.getContainersNames() == null || sniffer.getContainersNames().length == 0) {
+ report.failure(logger, "no container associated with application of type : " + sniffer.getModuleType(), null);
+ return null;
+ }
+
+ final String containerName = sniffer.getContainersNames()[0];
+ if (tracing!=null) {
+ tracing.addContainerMark(DeploymentTracing.ContainerMark.SNIFFER_DONE, containerName );
+ }
+
+
+ // start all the containers associated with sniffers.
+ EngineInfo engineInfo = containerRegistry.getContainer(containerName);
+ if (engineInfo == null) {
+ // need to synchronize on the registry to not end up starting the same container from
+ // different threads.
+ Collection<EngineInfo> containersInfo=null;
+ synchronized (containerRegistry) {
+ if (containerRegistry.getContainer(containerName) == null) {
+ if (tracing!=null) {
+ tracing.addContainerMark(
+ DeploymentTracing.ContainerMark.BEFORE_CONTAINER_SETUP, containerName );
+ }
+
+ containersInfo = setupContainer(sniffer, logger, context);
+ if (tracing!=null) {
+ tracing.addContainerMark(
+ DeploymentTracing.ContainerMark.AFTER_CONTAINER_SETUP, containerName );
+ }
+
+ if (containersInfo == null || containersInfo.size() == 0) {
+ String msg = "Cannot start container(s) associated to application of type : " + sniffer.getModuleType();
+ report.failure(logger, msg, null);
+ throw new Exception(msg);
+ }
+ }
+ }
+
+ // now start all containers, by now, they should be all setup...
+ if (containersInfo != null && !startContainers(containersInfo, logger, context)) {
+ final String msg = "Aborting, Failed to start container " + containerName;
+ report.failure(logger, msg, null);
+ throw new Exception(msg);
+ }
+ }
+ engineInfo = containerRegistry.getContainer(sniffer.getContainersNames()[0]);
+ if (tracing!=null) {
+ tracing.addContainerMark(
+ DeploymentTracing.ContainerMark.GOT_CONTAINER, containerName );
+ }
+
+ if (engineInfo ==null) {
+ final String msg = "Aborting, Failed to start container " + containerName;
+ report.failure(logger, msg, null);
+ throw new Exception(msg);
+ }
+ Deployer deployer = getDeployer(engineInfo);
+ if (deployer==null) {
+ if (!startContainers(Collections.singleton(engineInfo), logger, context)) {
+ final String msg = "Aborting, Failed to start container " + containerName;
+ report.failure(logger, msg, null);
+ throw new Exception(msg);
+ }
+ deployer = getDeployer(engineInfo);
+
+ if (deployer == null) {
+ report.failure(logger, "Got a null deployer out of the " + engineInfo.getContainer().getClass() + " container, is it annotated with @Service ?");
+ return null;
+ }
+ }
+ if (tracing!=null) {
+ tracing.addContainerMark(
+ DeploymentTracing.ContainerMark.GOT_DEPLOYER, containerName );
+ }
+
+ containerInfosByDeployers.put(deployer, engineInfo);
+ }
+
+ // all containers that have recognized parts of the application being deployed
+ // have now been successfully started. Start the deployment process.
+
+ List<ApplicationMetaDataProvider> providers = new LinkedList<ApplicationMetaDataProvider>();
+ providers.addAll(habitat.<ApplicationMetaDataProvider>getAllServices(ApplicationMetaDataProvider.class));
+
+ List<EngineInfo> sortedEngineInfos = new ArrayList<EngineInfo>();
+
+ Map<Class, ApplicationMetaDataProvider> typeByProvider = new HashMap<Class, ApplicationMetaDataProvider>();
+ for (ApplicationMetaDataProvider provider : habitat.<ApplicationMetaDataProvider>getAllServices(ApplicationMetaDataProvider.class)) {
+ if (provider.getMetaData()!=null) {
+ for (Class provided : provider.getMetaData().provides()) {
+ typeByProvider.put(provided, provider);
+ }
+ }
+ }
+
+ // check if everything is provided.
+ for (ApplicationMetaDataProvider provider : habitat.<ApplicationMetaDataProvider>getAllServices(ApplicationMetaDataProvider.class)) {
+ if (provider.getMetaData()!=null) {
+ for (Class dependency : provider.getMetaData().requires()) {
+ if (!typeByProvider.containsKey(dependency)) {
+ // at this point, I only log problems, because it maybe that what I am deploying now
+ // will not require this application metadata.
+ logger.log(Level.WARNING, KernelLoggerInfo.applicationMetaDataProvider,
+ new Object[] {provider, dependency});
+ }
+ }
+ }
+ }
+
+ Map<Class, Deployer> typeByDeployer = new HashMap<Class, Deployer>();
+ for (Deployer deployer : containerInfosByDeployers.keySet()) {
+ if (deployer.getMetaData()!=null) {
+ for (Class provided : deployer.getMetaData().provides()) {
+ typeByDeployer.put(provided, deployer);
+ }
+ }
+ }
+
+ for (Deployer deployer : containerInfosByDeployers.keySet()) {
+ if (deployer.getMetaData()!=null) {
+ for (Class dependency : deployer.getMetaData().requires()) {
+ if (!typeByDeployer.containsKey(dependency) && !typeByProvider.containsKey(dependency)) {
+
+ Service s = deployer.getClass().getAnnotation(Service.class);
+ String serviceName;
+ if (s!=null && s.name()!=null && s.name().length()>0) {
+ serviceName = s.name();
+ } else {
+ serviceName = deployer.getClass().getSimpleName();
+ }
+ report.failure(logger, serviceName + " deployer requires " + dependency + " but no other deployer provides it", null);
+ return null;
+ }
+ }
+ }
+ }
+
+ // ok everything is satisfied, just a matter of running things in order
+ List<Deployer> orderedDeployers = new ArrayList<Deployer>();
+ for (Deployer deployer : containerInfosByDeployers.keySet()) {
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("Keyed Deployer " + deployer.getClass());
+ }
+ loadDeployer(orderedDeployers, deployer, typeByDeployer, typeByProvider, context);
+ }
+
+ // now load metadata from deployers.
+ for (Deployer deployer : orderedDeployers) {
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("Ordered Deployer " + deployer.getClass());
+ }
+
+ final MetaData metadata = deployer.getMetaData();
+ try {
+ if (metadata!=null) {
+ if (metadata.provides()==null || metadata.provides().length==0) {
+ deployer.loadMetaData(null, context);
+ } else {
+ for (Class<?> provide : metadata.provides()) {
+ if (context.getModuleMetaData(provide)==null) {
+ context.addModuleMetaData(deployer.loadMetaData(provide, context));
+ } else {
+ deployer.loadMetaData(null, context);
+ }
+ }
+ }
+ } else {
+ deployer.loadMetaData(null, context);
+ }
+ } catch(Exception e) {
+ report.failure(logger, "Exception while invoking " + deployer.getClass() + " prepare method", e);
+ throw e;
+ }
+
+ sortedEngineInfos.add(containerInfosByDeployers.get(deployer));
+ }
+
+ return sortedEngineInfos;
+ }
+
+ private void loadDeployer(List<Deployer> results, Deployer deployer, Map<Class, Deployer> typeByDeployer, Map<Class, ApplicationMetaDataProvider> typeByProvider, DeploymentContext dc)
+ throws IOException {
+
+ if (results.contains(deployer)) {
+ return;
+ }
+ results.add(deployer);
+ if (deployer.getMetaData()!=null) {
+ for (Class required : deployer.getMetaData().requires()) {
+ if (dc.getModuleMetaData(required)!=null) {
+ continue;
+ }
+ if (typeByDeployer.containsKey(required)) {
+ loadDeployer(results,typeByDeployer.get(required), typeByDeployer, typeByProvider, dc);
+ } else {
+ ApplicationMetaDataProvider provider = typeByProvider.get(required);
+ if (provider==null) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.inconsistentLifecycleState, required);
+ } else {
+ LinkedList<ApplicationMetaDataProvider> providers = new LinkedList<ApplicationMetaDataProvider>();
+
+ addRecursively(providers, typeByProvider, provider);
+ for (ApplicationMetaDataProvider p : providers) {
+ dc.addModuleMetaData(p.load(dc));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void addRecursively(LinkedList<ApplicationMetaDataProvider> results, Map<Class, ApplicationMetaDataProvider> providers, ApplicationMetaDataProvider provider) {
+
+ results.addFirst(provider);
+ for (Class type : provider.getMetaData().requires()) {
+ if (providers.containsKey(type)) {
+ addRecursively(results, providers, providers.get(type));
+ }
+ }
+
+ }
+
+ public ModuleInfo prepareModule(
+ List<EngineInfo> sortedEngineInfos, String moduleName,
+ DeploymentContext context,
+ ProgressTracker tracker) throws Exception {
+
+ ActionReport report = context.getActionReport();
+ List<EngineRef> addedEngines = new ArrayList<EngineRef>();
+
+ DeploymentTracing tracing = context.getModuleMetaData(DeploymentTracing.class);
+
+ if (tracing!=null) {
+ tracing.addModuleMark(DeploymentTracing.ModuleMark.PREPARE,
+ moduleName);
+ }
+
+ for (EngineInfo engineInfo : sortedEngineInfos) {
+
+ // get the deployer
+ Deployer deployer = engineInfo.getDeployer();
+
+ try {
+ if (tracing!=null) {
+ tracing.addContainerMark(DeploymentTracing.ContainerMark.PREPARE,
+ engineInfo.getSniffer().getModuleType() );
+ }
+ deployer.prepare(context);
+ if (tracing!=null) {
+ tracing.addContainerMark(DeploymentTracing.ContainerMark.PREPARED,
+ engineInfo.getSniffer().getModuleType() );
+ }
+
+
+ // construct an incomplete EngineRef which will be later
+ // filled in at loading time
+ EngineRef engineRef = new EngineRef(engineInfo, null);
+ addedEngines.add(engineRef);
+ tracker.add("prepared", EngineRef.class, engineRef);
+
+ tracker.add(Deployer.class, deployer);
+ } catch(Exception e) {
+ report.failure(logger, "Exception while invoking " + deployer.getClass() + " prepare method", e);
+ throw e;
+ }
+ }
+ if (tracing!=null) {
+ tracing.addModuleMark(DeploymentTracing.ModuleMark.PREPARE_EVENTS, moduleName);
+ }
+
+ if (events!=null) {
+ events.send(new Event<DeploymentContext>(Deployment.MODULE_PREPARED, context), false);
+ }
+ if (tracing!=null) {
+ tracing.addModuleMark(DeploymentTracing.ModuleMark.PREPARED,moduleName);
+ }
+
+ // I need to create the application info here from the context, or something like this.
+ // and return the application info from this method for automatic registration in the caller.
+
+ // set isComposite property on module props so we know whether to persist
+ // module level properties inside ModuleInfo
+ String isComposite = context.getAppProps().getProperty(
+ ServerTags.IS_COMPOSITE);
+ if (isComposite != null) {
+ context.getModuleProps().setProperty(ServerTags.IS_COMPOSITE, isComposite);
+ }
+
+ ModuleInfo mi = new ModuleInfo(events, moduleName, addedEngines,
+ context.getModuleProps());
+
+ /*
+ * Save the application config that is potentially attached to each
+ * engine in the corresponding EngineRefs that have already created.
+ *
+ * Later, in registerAppInDomainXML, the appInfo is saved, which in
+ * turn saves the moduleInfo children and their engineRef children.
+ * Saving the engineRef assigns the application config to the Engine
+ * which corresponds directly to the <engine> element in the XML.
+ * A long way to get this done.
+ */
+
+// Application existingApp = applications.getModule(Application.class, moduleName);
+// if (existingApp != null) {
+ ApplicationConfigInfo savedAppConfig = new ApplicationConfigInfo(context.getAppProps());
+ for (EngineRef er : mi.getEngineRefs()) {
+ ApplicationConfig c = savedAppConfig.get(mi.getName(),
+ er.getContainerInfo().getSniffer().getModuleType());
+ if (c != null) {
+ er.setApplicationConfig(c);
+ }
+ }
+// }
+ return mi;
+ }
+
+ protected Collection<EngineInfo> setupContainer(Sniffer sniffer, Logger logger, DeploymentContext context) {
+ ActionReport report = context.getActionReport();
+ ContainerStarter starter = habitat.getService(ContainerStarter.class);
+ Collection<EngineInfo> containersInfo = starter.startContainer(sniffer);
+ if (containersInfo == null || containersInfo.size()==0) {
+ report.failure(logger, "Cannot start container(s) associated to application of type : " + sniffer.getModuleType(), null);
+ return null;
+ }
+ return containersInfo;
+ }
+
+ protected boolean startContainers(Collection<EngineInfo> containersInfo, Logger logger, DeploymentContext context) {
+
+ ActionReport report = context.getActionReport();
+ for (EngineInfo engineInfo : containersInfo) {
+ Container container;
+ try {
+ container = engineInfo.getContainer();
+ } catch(Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.cantStartContainer,
+ new Object[] {engineInfo.getSniffer().getModuleType(), e});
+ return false;
+ }
+
+ Class<? extends Deployer> deployerClass = container.getDeployer();
+ Deployer deployer;
+ try {
+ deployer = habitat.getService(deployerClass);
+ engineInfo.setDeployer(deployer);
+ } catch (MultiException e) {
+ report.failure(logger, "Cannot instantiate or inject "+deployerClass, e);
+ engineInfo.stop(logger);
+ return false;
+ } catch (ClassCastException e) {
+ engineInfo.stop(logger);
+ report.failure(logger, deployerClass+" does not implement " +
+ " the org.jvnet.glassfish.api.deployment.Deployer interface", e);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected void stopContainers(EngineInfo[] ctrInfos, Logger logger) {
+ for (EngineInfo ctrInfo : ctrInfos) {
+ try {
+ ctrInfo.stop(logger);
+ } catch(Exception e) {
+ // this is not a failure per se but we need to document it.
+ logger.log(Level.INFO, KernelLoggerInfo.cantReleaseContainer,
+ new Object[] {ctrInfo.getSniffer().getModuleType(), e});
+ }
+ }
+ }
+
+ public ApplicationInfo unload(ApplicationInfo info, ExtendedDeploymentContext context) {
+ ActionReport report = context.getActionReport();
+ if (info==null) {
+ report.failure(context.getLogger(), "Application not registered", null);
+ return null;
+ }
+
+ notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.STOP, context);
+
+ if (info.isLoaded()) {
+ info.stop(context, context.getLogger());
+ notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.STOP, context);
+
+ notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.UNLOAD, context);
+ info.unload(context);
+ notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.UNLOAD, context);
+ }
+
+ events.send(new Event<ApplicationInfo>(Deployment.APPLICATION_DISABLED, info), false);
+
+ try {
+ notifyLifecycleInterceptorsBefore(ExtendedDeploymentContext.Phase.CLEAN, context);
+ info.clean(context);
+ notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.CLEAN, context);
+ } catch(Exception e) {
+ report.failure(context.getLogger(), "Exception while cleaning", e);
+ return info;
+ }
+
+ return info;
+ }
+
+ public void undeploy(String appName, ExtendedDeploymentContext context) {
+
+ ActionReport report = context.getActionReport();
+ UndeployCommandParameters params = context.getCommandParameters(UndeployCommandParameters.class);
+
+ ApplicationInfo info = appRegistry.get(appName);
+ if (info==null) {
+ report.failure(context.getLogger(), "Application " + appName + " not registered", null);
+ events.send(new Event(Deployment.UNDEPLOYMENT_FAILURE, context));
+ return;
+
+ }
+
+ events.send(new Event(Deployment.UNDEPLOYMENT_START, info));
+
+ // for DAS target, the undeploy should unload the application
+ // as well
+ if (DeploymentUtils.isDASTarget(params.target)) {
+ unload(info, context);
+ }
+
+ if (report.getActionExitCode().equals(ActionReport.ExitCode.SUCCESS)) {
+ events.send(new Event(Deployment.UNDEPLOYMENT_SUCCESS, context));
+ deploymentLifecycleProbeProvider.applicationUndeployedEvent(appName, getApplicationType(info));
+ } else {
+ events.send(new Event(Deployment.UNDEPLOYMENT_FAILURE, context));
+ }
+
+ appRegistry.remove(appName);
+ }
+
+ // prepare application config change for later registering
+ // in the domain.xml
+ public Transaction prepareAppConfigChanges(final DeploymentContext context)
+ throws TransactionFailure {
+ final Properties appProps = context.getAppProps();
+ final DeployCommandParameters deployParams = context.getCommandParameters(DeployCommandParameters.class);
+ Transaction t = new Transaction();
+
+ try {
+ // prepare the application element
+ ConfigBean newBean = ((ConfigBean)ConfigBean.unwrap(applications)).allocate(Application.class);
+ Application app = newBean.createProxy();
+ Application app_w = t.enroll(app);
+ setInitialAppAttributes(app_w, deployParams, appProps, context);
+ context.addTransientAppMetaData(ServerTags.APPLICATION, app_w);
+ } catch(TransactionFailure e) {
+ t.rollback();
+ throw e;
+ } catch (Exception e) {
+ t.rollback();
+ throw new TransactionFailure(e.getMessage(), e);
+ }
+
+ return t;
+ }
+
+ // register application information in domain.xml
+ public void registerAppInDomainXML(final ApplicationInfo
+ applicationInfo, final DeploymentContext context, Transaction t)
+ throws TransactionFailure {
+ registerAppInDomainXML(applicationInfo, context, t, false);
+ }
+
+ // register application information in domain.xml
+ public void registerAppInDomainXML(final ApplicationInfo
+ applicationInfo, final DeploymentContext context, Transaction t,
+ boolean appRefOnly)
+ throws TransactionFailure {
+ final Properties appProps = context.getAppProps();
+ final DeployCommandParameters deployParams = context.getCommandParameters(DeployCommandParameters.class);
+ if (t != null) {
+ try {
+ if (!appRefOnly) {
+ Application app_w = context.getTransientAppMetaData(
+ ServerTags.APPLICATION, Application.class);
+ // adding the application element
+ setRestAppAttributes(app_w, appProps);
+ Applications apps_w = t.enroll(applications);
+ apps_w.getModules().add(app_w);
+ if (applicationInfo != null) {
+ applicationInfo.save(app_w);
+ }
+ }
+
+ List<String> targets = new ArrayList<String>();
+ if (!DeploymentUtils.isDomainTarget(deployParams.target)) {
+ targets.add(deployParams.target);
+ } else {
+ List<String> previousTargets = context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_TARGETS, List.class);
+ if (previousTargets == null) {
+ previousTargets = domain.getAllReferencedTargetsForApplication(deployParams.name);
+ }
+ targets = previousTargets;
+ }
+
+ String origVS = deployParams.virtualservers;
+ Boolean origEnabled = deployParams.enabled;
+ Properties previousVirtualServers = context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_VIRTUAL_SERVERS, Properties.class);
+ Properties previousEnabledAttributes = context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_ENABLED_ATTRIBUTES, Properties.class);
+ for (String target : targets) {
+ // first reset the virtualservers, enabled attribute
+ deployParams.virtualservers = origVS;
+ deployParams.enabled = origEnabled;
+ // now if the target is domain target,
+ // restore the previous attributes if
+ // applicable
+ if (DeploymentUtils.isDomainTarget(deployParams.target)) {
+ String vs = previousVirtualServers.getProperty(target);
+ if (vs != null) {
+ deployParams.virtualservers = vs;
+ }
+ String enabledAttr = previousEnabledAttributes.getProperty(target);
+ if (enabledAttr != null) {
+ deployParams.enabled = Boolean.valueOf(enabledAttr);
+ }
+ }
+ if (deployParams.enabled == null) {
+ deployParams.enabled = Boolean.TRUE;
+ }
+ Server servr = domain.getServerNamed(target);
+ if (servr != null) {
+ // adding the application-ref element to the standalone
+ // server instance
+ ConfigBeanProxy servr_w = t.enroll(servr);
+ // adding the application-ref element to the standalone
+ // server instance
+ ApplicationRef appRef = servr_w.createChild(ApplicationRef.class);
+ setAppRefAttributes(appRef, deployParams);
+ ((Server)servr_w).getApplicationRef().add(appRef);
+ }
+
+ Cluster cluster = domain.getClusterNamed(target);
+ if (cluster != null) {
+ // adding the application-ref element to the cluster
+ // and instances
+ ConfigBeanProxy cluster_w = t.enroll(cluster);
+ ApplicationRef appRef = cluster_w.createChild(ApplicationRef.class);
+ setAppRefAttributes(appRef, deployParams);
+ ((Cluster)cluster_w).getApplicationRef().add(appRef);
+
+ for (Server svr : cluster.getInstances() ) {
+ ConfigBeanProxy svr_w = t.enroll(svr);
+ ApplicationRef appRef2 = svr_w.createChild(ApplicationRef.class);
+ setAppRefAttributes(appRef2, deployParams);
+ ((Server)svr_w).getApplicationRef().add(appRef2);
+ }
+ }
+ }
+ } catch(TransactionFailure e) {
+ t.rollback();
+ throw e;
+ } catch (Exception e) {
+ t.rollback();
+ throw new TransactionFailure(e.getMessage(), e);
+ }
+
+ try {
+ t.commit();
+ } catch (RetryableException e) {
+ System.out.println("Retryable...");
+ // TODO : do something meaninful here
+ t.rollback();
+ } catch (TransactionFailure e) {
+ t.rollback();
+ throw e;
+ }
+ }
+ }
+
+ public void registerTenantWithAppInDomainXML(
+ final String appName,
+ final ExtendedDeploymentContext context) throws TransactionFailure {
+
+ final Transaction t = new Transaction();
+ try {
+ final AppTenant appTenant_w = writeableTenantForApp(
+ appName,
+ t);
+ appTenant_w.setContextRoot(context.getAppProps().getProperty(ServerTags.CONTEXT_ROOT));
+ appTenant_w.setTenant(context.getTenant());
+
+ t.commit();
+ } catch (TransactionFailure ex) {
+ t.rollback();
+ throw ex;
+ } catch (Throwable ex) {
+ t.rollback();
+ throw new TransactionFailure(ex.getLocalizedMessage(), ex);
+ }
+ }
+
+ public void unregisterTenantWithAppInDomainXML(
+ final String appName,
+ final String tenantName
+ ) throws TransactionFailure, RetryableException {
+ final com.sun.enterprise.config.serverbeans.Application app =
+ applications.getApplication(appName);
+ if (app == null) {
+ throw new IllegalArgumentException("Application " + appName + " not found");
+ }
+ final AppTenants appTenants = app.getAppTenants();
+ final AppTenant appTenant = appTenants.getAppTenant(tenantName);
+ if (appTenant == null) {
+ throw new IllegalArgumentException("Tenant " + tenantName + " not provisioned for application " + appName);
+ }
+ Transaction t = new Transaction();
+ final AppTenants appTenants_w = t.enroll(appTenants);
+ appTenants_w.getAppTenant().remove(appTenant);
+ t.commit();
+ }
+
+ private AppTenant writeableTenantForApp(
+ final String appName,
+ final Transaction t) throws TransactionFailure, PropertyVetoException {
+ final com.sun.enterprise.config.serverbeans.Application app =
+ applications.getApplication(appName);
+ if (app == null) {
+ throw new IllegalArgumentException("Application " + appName + " not found");
+ }
+
+ /*
+ * The app-tenants subelement might or might not already be there.
+ */
+ AppTenants appTenants = app.getAppTenants();
+ AppTenants appTenants_w;
+ if (appTenants == null) {
+ com.sun.enterprise.config.serverbeans.Application app_w =
+ t.enroll(app);
+ appTenants_w = app_w.createChild(AppTenants.class);
+ app_w.setAppTenants(appTenants_w);
+ } else {
+ appTenants_w = t.enroll(appTenants);
+ }
+
+ final List<AppTenant> appTenantList = appTenants_w.getAppTenant();
+ AppTenant appTenant_w = appTenants_w.createChild(AppTenant.class);
+ appTenantList.add(appTenant_w);
+ return appTenant_w;
+ }
+
+ // application attributes that are set in the beginning of the deployment
+ // that will not be changed in the course of the deployment
+ private void setInitialAppAttributes(Application app,
+ DeployCommandParameters deployParams, Properties appProps,
+ DeploymentContext context)
+ throws PropertyVetoException {
+ Properties previousEnabledAttributes = context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_ENABLED_ATTRIBUTES, Properties.class);
+ // various attributes
+ app.setName(deployParams.name);
+ if (deployParams.libraries != null) {
+ app.setLibraries(deployParams.libraries);
+ }
+ if (deployParams.description != null) {
+ app.setDescription(deployParams.description);
+ }
+ if (deployParams.deploymentorder != null) {
+ app.setDeploymentOrder(deployParams.deploymentorder.toString());
+ }
+
+ app.setEnabled(String.valueOf(true));
+ if (appProps.getProperty(ServerTags.LOCATION) != null) {
+ app.setLocation(appProps.getProperty(
+ ServerTags.LOCATION));
+ // when redeploy to domain we preserve the enable
+ // attribute
+ if (DeploymentUtils.isDomainTarget(deployParams.target)) {
+ if (previousEnabledAttributes != null) {
+ String enabledAttr = previousEnabledAttributes.getProperty(DeploymentUtils.DOMAIN_TARGET_NAME);
+ if (enabledAttr != null) {
+ app.setEnabled(enabledAttr);
+ }
+ }
+ }
+ app.setAvailabilityEnabled(deployParams.availabilityenabled.toString());
+ app.setAsyncReplication(deployParams.asyncreplication.toString());
+ }
+ if (appProps.getProperty(ServerTags.OBJECT_TYPE) != null) {
+ app.setObjectType(appProps.getProperty(
+ ServerTags.OBJECT_TYPE));
+ }
+ if (appProps.getProperty(ServerTags.DIRECTORY_DEPLOYED)
+ != null) {
+ app.setDirectoryDeployed(appProps.getProperty(
+ ServerTags.DIRECTORY_DEPLOYED));
+ }
+ }
+
+
+ // set the rest of the application attributes at the end of the
+ // deployment
+ private void setRestAppAttributes(Application app, Properties appProps)
+ throws PropertyVetoException, TransactionFailure {
+ // context-root element
+ if (appProps.getProperty(ServerTags.CONTEXT_ROOT) != null) {
+ app.setContextRoot(appProps.getProperty(
+ ServerTags.CONTEXT_ROOT));
+ }
+ // property element
+ // trim the properties that have been written as attributes
+ // the rest properties will be written as property element
+ for (Iterator itr = appProps.keySet().iterator();
+ itr.hasNext();) {
+ String propName = (String) itr.next();
+ if (!propName.equals(ServerTags.LOCATION) &&
+ !propName.equals(ServerTags.CONTEXT_ROOT) &&
+ !propName.equals(ServerTags.OBJECT_TYPE) &&
+ !propName.equals(ServerTags.DIRECTORY_DEPLOYED) &&
+ !propName.startsWith(
+ DeploymentProperties.APP_CONFIG))
+ {
+ if (appProps.getProperty(propName) != null) {
+ Property prop = app.createChild(Property.class);
+ app.getProperty().add(prop);
+ prop.setName(propName);
+ prop.setValue(appProps.getProperty(propName));
+ }
+ }
+ }
+ }
+
+ public void unregisterAppFromDomainXML(final String appName,
+ final String target) throws TransactionFailure {
+ unregisterAppFromDomainXML(appName, target, false);
+ }
+
+ public void unregisterAppFromDomainXML(final String appName,
+ final String tgt, final boolean appRefOnly)
+ throws TransactionFailure {
+ ConfigSupport.apply(new SingleConfigCode() {
+ public Object run(ConfigBeanProxy param) throws PropertyVetoException, TransactionFailure {
+ // get the transaction
+ Transaction t = Transaction.getTransaction(param);
+ if (t!=null) {
+ List<String> targets = new ArrayList<String>();
+ if (!DeploymentUtils.isDomainTarget(tgt)) {
+ targets.add(tgt);
+ } else {
+ targets = domain.getAllReferencedTargetsForApplication(appName);
+ }
+
+ Domain dmn;
+ if (param instanceof Domain) {
+ dmn = (Domain)param;
+ } else {
+ return Boolean.FALSE;
+ }
+
+ for (String target : targets) {
+ Server servr = dmn.getServerNamed(target);
+ if (servr != null) {
+ // remove the application-ref from standalone
+ // server instance
+ ConfigBeanProxy servr_w = t.enroll(servr);
+ for (ApplicationRef appRef :
+ servr.getApplicationRef()) {
+ if (appRef.getRef().equals(appName)) {
+ ((Server)servr_w).getApplicationRef().remove(
+ appRef);
+ break;
+ }
+ }
+ }
+
+ Cluster cluster = dmn.getClusterNamed(target);
+ if (cluster != null) {
+ // remove the application-ref from cluster
+ ConfigBeanProxy cluster_w = t.enroll(cluster);
+ for (ApplicationRef appRef :
+ cluster.getApplicationRef()) {
+ if (appRef.getRef().equals(appName)) {
+ ((Cluster)cluster_w).getApplicationRef().remove(
+ appRef);
+ break;
+ }
+ }
+
+ // remove the application-ref from cluster instances
+ for (Server svr : cluster.getInstances() ) {
+ ConfigBeanProxy svr_w = t.enroll(svr);
+ for (ApplicationRef appRef :
+ svr.getApplicationRef()) {
+ if (appRef.getRef().equals(appName)) {
+ ((Server)svr_w).getApplicationRef(
+ ).remove(appRef);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!appRefOnly) {
+ // remove application element
+ Applications apps = dmn.getApplications();
+ ConfigBeanProxy apps_w = t.enroll(apps);
+ for (ApplicationName module : apps.getModules()) {
+ if (module.getName().equals(appName)) {
+ ((Applications)apps_w).getModules().remove(module);
+ break;
+ }
+ }
+ }
+ }
+ return Boolean.TRUE;
+ }
+ }, domain);
+ }
+
+
+ public void updateAppEnabledAttributeInDomainXML(final String appName,
+ final String target, final boolean enabled) throws TransactionFailure {
+ ConfigSupport.apply(new SingleConfigCode() {
+ public Object run(ConfigBeanProxy param) throws PropertyVetoException, TransactionFailure {
+ // get the transaction
+ Transaction t = Transaction.getTransaction(param);
+ if (t!=null) {
+ Domain dmn;
+ if (param instanceof Domain) {
+ dmn = (Domain)param;
+ } else {
+ return Boolean.FALSE;
+ }
+
+ if (enabled || DeploymentUtils.isDomainTarget(target)) {
+ Application app = dmn.getApplications().getApplication(appName);
+ ConfigBeanProxy app_w = t.enroll(app);
+ ((Application)app_w).setEnabled(String.valueOf(enabled));
+
+ }
+
+ List<String> targets = new ArrayList<String>();
+ if (!DeploymentUtils.isDomainTarget(target)) {
+ targets.add(target);
+ } else {
+ targets = domain.getAllReferencedTargetsForApplication(appName);
+ }
+
+ for (String target : targets) {
+ Server servr = dmn.getServerNamed(target);
+ if (servr != null) {
+ // update the application-ref from standalone
+ // server instance
+ for (ApplicationRef appRef :
+ servr.getApplicationRef()) {
+ if (appRef.getRef().equals(appName)) {
+ ConfigBeanProxy appRef_w = t.enroll(appRef);
+ ((ApplicationRef)appRef_w).setEnabled(String.valueOf(enabled));
+ break;
+ }
+ }
+ updateClusterAppRefWithInstanceUpdate(t, servr, appName, enabled);
+ }
+ Cluster cluster = dmn.getClusterNamed(target);
+ if (cluster != null) {
+ // update the application-ref from cluster
+ for (ApplicationRef appRef :
+ cluster.getApplicationRef()) {
+ if (appRef.getRef().equals(appName)) {
+ ConfigBeanProxy appRef_w = t.enroll(appRef);
+ ((ApplicationRef)appRef_w).setEnabled(String.valueOf(enabled));
+ break;
+ }
+ }
+
+ // update the application-ref from cluster instances
+ for (Server svr : cluster.getInstances() ) {
+ for (ApplicationRef appRef :
+ svr.getApplicationRef()) {
+ if (appRef.getRef().equals(appName)) {
+ ConfigBeanProxy appRef_w = t.enroll(appRef);
+ ((ApplicationRef)appRef_w).setEnabled(String.valueOf(enabled));
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return Boolean.TRUE;
+ }
+ }, domain);
+ }
+
+ // check if the application is registered in domain.xml
+ public boolean isRegistered(String appName) {
+ return applications.getApplication(appName)!=null;
+ }
+
+ public ApplicationInfo get(String appName) {
+ return appRegistry.get(appName);
+ }
+
+ private boolean isPaaSEnabled(Boolean isClassicStyle) {
+ if (isClassicStyle) {
+ return false;
+ }
+
+ if (virtEnv != null && virtEnv.isPaasEnabled()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ // gets the default target when no target is specified for non-paas case
+ public String getDefaultTarget(Boolean isClassicStyle) {
+ if (!isPaaSEnabled(isClassicStyle)) {
+ return DeploymentUtils.DAS_TARGET_NAME;
+ }
+ return null;
+ }
+
+ // gets the default target when no target is specified
+ public String getDefaultTarget(String appName, OpsParams.Origin origin, Boolean isClassicStyle) {
+ if (!isPaaSEnabled(isClassicStyle)) {
+ return DeploymentUtils.DAS_TARGET_NAME;
+ } else {
+ // for deploy case, OE will set the deploy target later
+ if (origin == OpsParams.Origin.deploy) {
+ return null;
+ }
+ // for other cases, we try to derive it from domain.xml
+ List<String> targets =
+ domain.getAllReferencedTargetsForApplication(appName);
+ if (targets.size() == 0) {
+ throw new IllegalArgumentException("Application not registered");
+ }
+ if (targets.size() > 1) {
+ throw new IllegalArgumentException("Cannot determine the default target. Please specify an explicit target for the operation.");
+ }
+ return targets.get(0);
+ }
+ }
+
+ public class DeploymentContextBuidlerImpl implements DeploymentContextBuilder {
+ private final Logger logger;
+ private final ActionReport report;
+ private final OpsParams params;
+ private File sFile;
+ private ReadableArchive sArchive;
+ private ArchiveHandler handler;
+
+ public DeploymentContextBuidlerImpl(Logger logger, OpsParams params, ActionReport report) {
+ this.logger = logger;
+ this.report = report;
+ this.params = params;
+ }
+
+ public DeploymentContextBuidlerImpl(DeploymentContextBuilder b) throws IOException {
+ this.logger = b.logger();
+ this.report = b.report();
+ this.params = b.params();
+ ReadableArchive archive = getArchive(b);
+ source(archive);
+ handler = b.archiveHandler();
+ }
+
+ public DeploymentContextBuilder source(File source) {
+ this.sFile = source;
+ return this;
+ }
+
+ public File sourceAsFile() {
+ return sFile;
+ }
+ public ReadableArchive sourceAsArchive() {
+ return sArchive;
+ }
+
+ public ArchiveHandler archiveHandler() {
+ return handler;
+ }
+
+ public DeploymentContextBuilder source(ReadableArchive archive) {
+ this.sArchive = archive;
+ return this;
+ }
+
+ public DeploymentContextBuilder archiveHandler(ArchiveHandler handler) {
+ this.handler = handler;
+ return this;
+ }
+
+ public ExtendedDeploymentContext build() throws IOException {
+ return build(null);
+ }
+ public Logger logger() { return logger; };
+ public ActionReport report() { return report; };
+ public OpsParams params() { return params; };
+
+ public ExtendedDeploymentContext build(ExtendedDeploymentContext initialContext) throws IOException {
+ return ApplicationLifecycle.this.getContext(initialContext, this);
+ }
+ }
+
+ public DeploymentContextBuilder getBuilder(Logger logger, OpsParams params, ActionReport report) {
+ return new DeploymentContextBuidlerImpl(logger, params, report);
+ }
+
+ /**
+ * Updates the "enabled" setting of the cluster's app ref for the
+ * given app if a change to the "enabled" setting of the app ref on one of
+ * the cluster's instances implies a cluster-level change.
+ * <p>
+ * If the app is enabled on any single instance in a cluster
+ * then the cluster state needs to be enabled. If
+ * the app is disabled on all instances in the cluster
+ * then the cluster state should be disabled. This method makes sure the
+ * cluster-level app ref enabled state is correct, given the current values
+ * of the app refs on the cluster's instances combined with the new value
+ * for the specified instance.
+ *
+ * @param t current config Transaction in progress
+ * @param servr the Server for which the app ref has been enabled or disabled
+ * @param appName the name of the app whose app ref has been enabled or disabled
+ * @param isNewInstanceAppRefStateEnabled whether the new instance app ref state is enabled (false if disabled)
+ */
+ private void updateClusterAppRefWithInstanceUpdate(
+ final Transaction t,
+ final Server servr,
+ final String appName,
+ final boolean isNewInstanceAppRefStateEnabled)
+ throws TransactionFailure, PropertyVetoException {
+ final Cluster clusterContainingInstance = servr.getCluster();
+ if (clusterContainingInstance != null) {
+ /*
+ * Update the cluster state also if needed.
+ */
+ boolean isAppRefEnabledOnAnyClusterInstance = false;
+ for (Server inst : clusterContainingInstance.getInstances()) {
+ /*
+ * The app ref for the server just changed above
+ * still has its old state when fetched using
+ * inst.getApplicationRef(appName). So when we
+ * encounter the same server in the list of
+ * cluster instances, use the "enabled" value --
+ * which we just used above to update the app ref
+ * for the targeted instance -- below when
+ * we need to consider the "enabled" value for the
+ * just-changed instance.
+ */
+ isAppRefEnabledOnAnyClusterInstance |= (
+ servr.getName().equals(inst.getName())
+ ? isNewInstanceAppRefStateEnabled
+ : Boolean.parseBoolean(inst.getApplicationRef(appName).getEnabled()));
+ }
+ final ApplicationRef clusterAppRef =
+ clusterContainingInstance.getApplicationRef(appName);
+ if (Boolean.parseBoolean(clusterAppRef.getEnabled()) != isAppRefEnabledOnAnyClusterInstance) {
+ t.enroll(clusterAppRef).setEnabled(String.valueOf(isAppRefEnabledOnAnyClusterInstance));
+ }
+ }
+ }
+
+ // cannot put it on the builder itself since the builder is an official API.
+ private ReadableArchive getArchive(DeploymentContextBuilder builder) throws IOException {
+ ReadableArchive archive = builder.sourceAsArchive();
+ if (archive==null && builder.sourceAsFile()==null) {
+ throw new IOException("Source archive or file not provided to builder");
+ }
+ if (archive==null && builder.sourceAsFile()!=null) {
+ archive = habitat.<ArchiveFactory>getService(ArchiveFactory.class).openArchive(builder.sourceAsFile());
+ if (archive==null) {
+ throw new IOException("Invalid archive type : " + builder.sourceAsFile().getAbsolutePath());
+ }
+ }
+ return archive;
+ }
+
+ private ExtendedDeploymentContext getContext(ExtendedDeploymentContext initial, DeploymentContextBuilder builder) throws IOException {
+
+ DeploymentContextBuilder copy = new DeploymentContextBuidlerImpl(builder);
+
+ ReadableArchive archive = getArchive(copy);
+ copy.source(archive);
+
+ if (initial==null) {
+ initial = new DeploymentContextImpl(copy, env);
+ }
+
+ ArchiveHandler archiveHandler = copy.archiveHandler();
+ if (archiveHandler == null) {
+ String type = null;
+ OpsParams params = builder.params();
+ if (params != null) {
+ if (params instanceof DeployCommandParameters) {
+ type = ((DeployCommandParameters)params).type;
+ } else if (params instanceof UndeployCommandParameters) {
+ type = ((UndeployCommandParameters)params)._type;
+ }
+ }
+ archiveHandler = getArchiveHandler(archive, type);
+ }
+
+
+
+ // this is needed for autoundeploy to find the application
+ // with the archive name
+ File sourceFile = new File(archive.getURI().getSchemeSpecificPart());
+ initial.getAppProps().put(ServerTags.DEFAULT_APP_NAME,
+ DeploymentUtils.getDefaultEEName(sourceFile.getName()));
+
+ if (!(sourceFile.isDirectory())) {
+
+ String repositoryBitName = copy.params().name();
+ try {
+ repositoryBitName = VersioningUtils.getRepositoryName(repositoryBitName);
+ } catch (VersioningSyntaxException e) {
+ ActionReport report = copy.report();
+ report.setMessage(e.getMessage());
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ }
+
+ // create a temporary deployment context
+ File expansionDir = new File(domain.getApplicationRoot(),
+ repositoryBitName);
+ if (!expansionDir.mkdirs()) {
+ /*
+ * On Windows especially a previous directory might have
+ * remainded after an earlier undeployment, for example if
+ * a JAR file in the earlier deployment had been locked.
+ * Warn but do not fail in such a case.
+ */
+ logger.fine(localStrings.getLocalString("deploy.cannotcreateexpansiondir", "Error while creating directory for jar expansion: {0}",expansionDir));
+ }
+ try {
+ Long start = System.currentTimeMillis();
+ final WritableArchive expandedArchive = archiveFactory.createArchive(expansionDir);
+ archiveHandler.expand(archive, expandedArchive, initial);
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("Deployment expansion took " + (System.currentTimeMillis() - start));
+ }
+
+ // Close the JAR archive before losing the reference to it or else the JAR remains locked.
+ try {
+ archive.close();
+ } catch(IOException e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.errorClosingArtifact,
+ new Object[] { archive.getURI().getSchemeSpecificPart(), e});
+ throw e;
+ }
+ archive = (FileArchive) expandedArchive;
+ initial.setSource(archive);
+ } catch(IOException e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.errorExpandingFile, e);
+ throw e;
+ }
+ }
+ initial.setArchiveHandler(archiveHandler);
+ return initial;
+ }
+
+ private void setAppRefAttributes(ApplicationRef appRef,
+ DeployCommandParameters deployParams)
+ throws PropertyVetoException {
+ appRef.setRef(deployParams.name);
+ if (deployParams.virtualservers != null) {
+ appRef.setVirtualServers(deployParams.virtualservers);
+ } else {
+ // deploy to all virtual-servers, we need to get the list.
+ appRef.setVirtualServers(DeploymentUtils.getVirtualServers(deployParams.target, env, domain));
+ }
+ if(deployParams.lbenabled != null){
+ appRef.setLbEnabled(deployParams.lbenabled);
+ } else {
+ //check if system property exists and use that
+ String lbEnabledDefault =
+ System.getProperty(Server.lbEnabledSystemProperty);
+ if (lbEnabledDefault != null) {
+ appRef.setLbEnabled(lbEnabledDefault);
+ }
+ }
+ appRef.setEnabled(deployParams.enabled.toString());
+ }
+
+ public ParameterMap prepareInstanceDeployParamMap(DeploymentContext dc)
+ throws Exception {
+ final DeployCommandParameters params = dc.getCommandParameters(DeployCommandParameters.class);
+ final Collection<String> excludedParams = new ArrayList<String>();
+ excludedParams.add(DeploymentProperties.PATH);
+ excludedParams.add(DeploymentProperties.DEPLOYMENT_PLAN);
+ excludedParams.add(DeploymentProperties.ALT_DD);
+ excludedParams.add(DeploymentProperties.RUNTIME_ALT_DD);
+ excludedParams.add(DeploymentProperties.UPLOAD); // We'll force it to true ourselves.
+
+ final ParameterMap paramMap;
+ final ParameterMapExtractor extractor = new ParameterMapExtractor(params);
+ paramMap = extractor.extract(excludedParams);
+
+ prepareGeneratedContent(dc, paramMap);
+
+ // set the path and plan params
+
+ // get the location properties from the application so the token
+ // will be resolved
+ Application application = applications.getApplication(params.name);
+ Properties appProperties = application.getDeployProperties();
+ String archiveLocation = appProperties.getProperty(Application.APP_LOCATION_PROP_NAME);
+ final File archiveFile = new File(new URI(archiveLocation));
+ paramMap.set("DEFAULT", archiveFile.getAbsolutePath());
+
+ String planLocation = appProperties.getProperty(Application.DEPLOYMENT_PLAN_LOCATION_PROP_NAME);
+ if (planLocation != null) {
+ final File actualPlan = new File(new URI(planLocation));
+ paramMap.set(DeployCommandParameters.ParameterNames.DEPLOYMENT_PLAN, actualPlan.getAbsolutePath());
+ }
+
+ String altDDLocation = appProperties.getProperty(Application.ALT_DD_LOCATION_PROP_NAME);
+ if (altDDLocation != null) {
+ final File altDD = new File(new URI(altDDLocation));
+ paramMap.set(DeployCommandParameters.ParameterNames.ALT_DD, altDD.getAbsolutePath());
+ }
+
+ String runtimeAltDDLocation = appProperties.getProperty(Application.RUNTIME_ALT_DD_LOCATION_PROP_NAME);
+ if (runtimeAltDDLocation != null) {
+ final File runtimeAltDD = new File(new URI(runtimeAltDDLocation));
+ paramMap.set(DeployCommandParameters.ParameterNames.RUNTIME_ALT_DD, runtimeAltDD.getAbsolutePath());
+ }
+
+ // always upload the archives to the instance side
+ // but not directories. Note that we prepare a zip file containing
+ // the generated directories and pass that as a single parameter so it
+ // will be uploaded even though a deployment directory is not.
+ paramMap.set(DeploymentProperties.UPLOAD, "true");
+
+ // pass the params we restored from the previous deployment in case of
+ // redeployment
+ if (params.previousContextRoot != null) {
+ paramMap.set(DeploymentProperties.PRESERVED_CONTEXT_ROOT, params.previousContextRoot);
+ }
+
+ // pass the app props so we have the information to persist in the
+ // domain.xml
+ Properties appProps = dc.getAppProps();
+ appProps.remove(DeploymentProperties.APP_CONFIG);
+ paramMap.set(DeploymentProperties.APP_PROPS, extractor.propertiesValue(appProps, ':'));
+
+ Properties previousVirtualServers = dc.getTransientAppMetaData(DeploymentProperties.PREVIOUS_VIRTUAL_SERVERS, Properties.class);
+ if (previousVirtualServers != null) {
+ paramMap.set(DeploymentProperties.PREVIOUS_VIRTUAL_SERVERS, extractor.propertiesValue(previousVirtualServers, ':'));
+ }
+
+ Properties previousEnabledAttributes = dc.getTransientAppMetaData(DeploymentProperties.PREVIOUS_ENABLED_ATTRIBUTES, Properties.class);
+ if (previousEnabledAttributes != null) {
+ paramMap.set(DeploymentProperties.PREVIOUS_ENABLED_ATTRIBUTES, extractor.propertiesValue(previousEnabledAttributes, ':'));
+ }
+
+ return paramMap;
+ }
+
+ private void prepareGeneratedContent(final DeploymentContext dc,
+ final ParameterMap paramMap) throws IOException {
+
+ /*
+ * Create a single ZIP file containing the various generated
+ * directories for this app.
+ *
+ * Note that some deployments - such as of OSGI modules - might not
+ * create any generated content.
+ */
+ final File generatedContentZip = createGeneratedContentZip();
+
+ ZipOutputStream zipOS = null;
+
+ /*
+ * We want the ZIP file to contain xml/(appname), ejb/(appname), etc.
+ * directories, even if those directories don't contain anything.
+ * Then the instance deploy command can expand the uploaded zip file
+ * based at the instance's generated/ directory and the files - including
+ * empty directories if appropriate - will be stored in the right places.
+ */
+ final File baseDir = dc.getScratchDir("xml").getParentFile().getParentFile();
+
+ for (String scratchType : UPLOADED_GENERATED_DIRS) {
+
+ zipOS = addScratchContentIfPresent(dc, baseDir, zipOS, generatedContentZip, scratchType);
+ }
+
+ if (zipOS != null) {
+ /*
+ * Because we did zip up some generated content, add the just-generated
+ * zip file as a parameter to the param map.
+ */
+ zipOS.close();
+ // set the generated content param
+ paramMap.set("generatedcontent", generatedContentZip.getAbsolutePath());
+ }
+ }
+
+ private File createGeneratedContentZip() throws IOException {
+ final File tempFile = File.createTempFile("gendContent", ".zip");
+ tempFile.deleteOnExit();
+ return tempFile;
+ }
+
+ private ZipOutputStream addScratchContentIfPresent(final DeploymentContext dc,
+ final File baseDir,
+ ZipOutputStream zipOS,
+ final File generatedContentZip,
+ final String scratchDirName) throws IOException {
+ final File genDir = dc.getScratchDir(scratchDirName);
+ if (genDir.isDirectory()) {
+ if (zipOS == null) {
+ zipOS = new ZipOutputStream(
+ new BufferedOutputStream(new FileOutputStream(generatedContentZip)));
+ }
+ addFileToZip(zipOS, baseDir, genDir);
+ }
+ return zipOS;
+ }
+
+ private void addFileToZip(final ZipOutputStream zipOS, final File baseDir, final File f) throws IOException {
+ final String entryName = baseDir.toURI().relativize(f.toURI()).getPath();
+ final ZipEntry entry = new ZipEntry(entryName);
+ zipOS.putNextEntry(entry);
+ if ( ! f.isDirectory()) {
+ final byte[] buffer = new byte[1024];
+ final InputStream is = new BufferedInputStream(new FileInputStream(f));
+ int bytesRead;
+ try {
+ while ((bytesRead = is.read(buffer)) != -1) {
+ zipOS.write(buffer, 0, bytesRead);
+ }
+ } finally {
+ is.close();
+ zipOS.closeEntry();
+ }
+ } else {
+ /*
+ * A directory entry has no content itself.
+ */
+ zipOS.closeEntry();
+ for (File subFile : f.listFiles()) {
+ addFileToZip(zipOS, baseDir, subFile);
+ }
+ }
+ }
+
+ public void validateDeploymentTarget(String target, String name,
+ boolean isRedeploy) {
+ List<String> referencedTargets = domain.getAllReferencedTargetsForApplication(name);
+ if (referencedTargets.isEmpty()) {
+ if (isRegistered(name)) {
+ if (!isRedeploy && DeploymentUtils.isDomainTarget(target)) {
+ throw new IllegalArgumentException(localStrings.getLocalString("application.alreadyreg.redeploy", "Application with name {0} is already registered. Either specify that redeployment must be forced, or redeploy the application. Or if this is a new deployment, pick a different name.", name));
+ } else {
+ if (!DeploymentUtils.isDomainTarget(target)) {
+ throw new IllegalArgumentException(localStrings.getLocalString("use.create_app_ref_2", "Application {0} is already deployed in this domain. Please use create application ref to create application reference on target {1}.", name, target));
+ }
+ }
+ }
+ return;
+ }
+ if (!isRedeploy) {
+ if (DeploymentUtils.isDomainTarget(target)) {
+ throw new IllegalArgumentException(localStrings.getLocalString("application.deploy_domain", "Application with name {0} is already referenced by other target(s). Please specify force option to redeploy to domain.", name));
+ }
+ if (referencedTargets.size() == 1 &&
+ referencedTargets.contains(target)) {
+ throw new IllegalArgumentException(localStrings.getLocalString("application.alreadyreg.redeploy", "Application with name {0} is already registered. Either specify that redeployment must be forced, or redeploy the application. Or if this is a new deployment, pick a different name.", name));
+ } else {
+ throw new IllegalArgumentException(localStrings.getLocalString("use.create_app_ref", "Application {0} is already referenced by other target(s). Please use create application ref to create application reference on target {1}.", name, target));
+ }
+ } else {
+ if (referencedTargets.size() == 1 &&
+ referencedTargets.contains(target)) {
+ return;
+ } else {
+ if (!DeploymentUtils.isDomainTarget(target)) {
+ throw new IllegalArgumentException(localStrings.getLocalString("redeploy_on_multiple_targets", "Application {0} is referenced by more than one targets. Please remove other references or specify all targets (or domain target if using asadmin command line) before attempting redeploy operation.", name));
+ }
+ }
+ }
+ }
+
+ public void validateUndeploymentTarget(String target, String name) {
+ List<String> referencedTargets = domain.getAllReferencedTargetsForApplication(name);
+ if (referencedTargets.size() > 1) {
+ Application app = applications.getApplication(name);
+ if (!DeploymentUtils.isDomainTarget(target)) {
+ if (app.isLifecycleModule()) {
+ throw new IllegalArgumentException(localStrings.getLocalString("delete_lifecycle_on_multiple_targets", "Lifecycle module {0} is referenced by more than one targets. Please remove other references before attempting delete operation.", name));
+ } else {
+ throw new IllegalArgumentException(localStrings.getLocalString("undeploy_on_multiple_targets", "Application {0} is referenced by more than one targets. Please remove other references or specify all targets (or domain target if using asadmin command line) before attempting undeploy operation.", name));
+ }
+ }
+ }
+ }
+
+ public void validateSpecifiedTarget(String target) {
+ if (env.isDas()) {
+ if (target == null) {
+ // we only validate the specified target
+ return;
+ }
+ Cluster cluster = domain.getClusterNamed(target);
+ if (cluster != null) {
+ if (cluster.isVirtual()) {
+ throw new IllegalArgumentException(localStrings.getLocalString("cannot_specify_managed_target", "Cannot specify target {0} for the operation. Target {0} is a managed target.", target));
+ }
+ }
+ }
+ }
+
+ public boolean isAppEnabled(Application app) {
+ if (Boolean.valueOf(app.getEnabled())) {
+ ApplicationRef appRef = server.getApplicationRef(app.getName());
+ if (appRef != null && Boolean.valueOf(appRef.getEnabled())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public ExtendedDeploymentContext disable(UndeployCommandParameters commandParams,
+ Application app, ApplicationInfo appInfo, ActionReport report,
+ Logger logger) throws Exception {
+ if (appInfo == null) {
+ return null;
+ }
+
+ // if it's not on DAS and the application is not loaded, do not unload
+ // when it's on DAS, there is some necessary clean up we need to do
+ if (!env.isDas() && !appInfo.isLoaded()) {
+ return null;
+ }
+
+ if (app != null) {
+ commandParams._type = app.archiveType();
+ }
+
+ final ExtendedDeploymentContext deploymentContext =
+ getBuilder(logger, commandParams, report).source(appInfo.getSource()).build();
+
+ if (app != null) {
+ deploymentContext.getAppProps().putAll(
+ app.getDeployProperties());
+ deploymentContext.setModulePropsMap(
+ app.getModulePropertiesMap());
+ }
+
+ if (commandParams.properties != null) {
+ deploymentContext.getAppProps().putAll(commandParams.properties);
+ }
+
+ unload(appInfo, deploymentContext);
+ return deploymentContext;
+ }
+
+ public ExtendedDeploymentContext enable(String target, Application app, ApplicationRef appRef,
+ ActionReport report, Logger logger) throws Exception {
+ ReadableArchive archive = null;
+ try {
+ DeployCommandParameters commandParams = app.getDeployParameters(appRef);
+ // if the application is already loaded, do not load again
+ ApplicationInfo appInfo = appRegistry.get(commandParams.name);
+ if (appInfo != null && appInfo.isLoaded()) {
+ return null;
+ }
+ commandParams.origin = DeployCommandParameters.Origin.load;
+ commandParams.command = DeployCommandParameters.Command.enable;
+ commandParams.target = target;
+ commandParams.enabled = Boolean.TRUE;
+ Properties contextProps = app.getDeployProperties();
+ Map<String, Properties> modulePropsMap = app.getModulePropertiesMap();
+ ApplicationConfigInfo savedAppConfig = new ApplicationConfigInfo(app);
+ URI uri = new URI(app.getLocation());
+ File file = new File(uri);
+
+ if (!file.exists()) {
+ throw new Exception(localStrings.getLocalString("fnf", "File not found {0}", file.getAbsolutePath()));
+ }
+
+ archive = archiveFactory.openArchive(file);
+
+ final ExtendedDeploymentContext deploymentContext =
+ getBuilder(logger, commandParams, report).source(archive).build();
+
+ Properties appProps = deploymentContext.getAppProps();
+ appProps.putAll(contextProps);
+ savedAppConfig.store(appProps);
+
+ if (modulePropsMap != null) {
+ deploymentContext.setModulePropsMap(modulePropsMap);
+ }
+
+ deploy(getSniffersFromApp(app), deploymentContext);
+ return deploymentContext;
+ } finally {
+ try {
+ if (archive != null) {
+ archive.close();
+ }
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+ }
+
+ private boolean loadOnCurrentInstance(DeploymentContext context) {
+ final DeployCommandParameters commandParams = context.getCommandParameters(DeployCommandParameters.class);
+ final Properties appProps = context.getAppProps();
+ if (commandParams.enabled) {
+ // if the current instance match with the target
+ if (domain.isCurrentInstanceMatchingTarget(commandParams.target, commandParams.name(), server.getName(), context.getTransientAppMetaData(DeploymentProperties.PREVIOUS_TARGETS, List.class))) {
+ return true;
+ }
+ if (server.isDas()) {
+ String objectType =
+ appProps.getProperty(ServerTags.OBJECT_TYPE);
+ if (objectType != null) {
+ // if it's a system application needs to be loaded on DAS
+ if (objectType.equals(DeploymentProperties.SYSTEM_ADMIN) ||
+ objectType.equals(DeploymentProperties.SYSTEM_ALL)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private String getApplicationType(ApplicationInfo appInfo) {
+ StringBuffer sb = new StringBuffer();
+ if (appInfo.getSniffers().size() > 0) {
+ for (Sniffer sniffer : appInfo.getSniffers()) {
+ if (sniffer.isUserVisible()) {
+ sb.append(sniffer.getModuleType() + ", ");
+ }
+ }
+ }
+ if (sb.length() > 2) {
+ return sb.substring(0, sb.length()-2);
+ }
+ return sb.toString();
+ }
+
+ public List<Sniffer> getSniffersFromApp(Application app) {
+ List<String> snifferTypes = new ArrayList<String>();
+ for (com.sun.enterprise.config.serverbeans.Module module : app.getModule()) {
+ for (Engine engine : module.getEngines()) {
+ snifferTypes.add(engine.getSniffer());
+ }
+ }
+
+ if (snifferTypes.isEmpty()) {
+ // for the upgrade scenario, we cannot get the sniffers from the
+ // domain.xml, so we need to re-process it during deployment
+ return null;
+ }
+
+ List<Sniffer> sniffers = new ArrayList<Sniffer>();
+ if (app.isStandaloneModule()) {
+ for (String snifferType : snifferTypes) {
+ Sniffer sniffer = snifferManager.getSniffer(snifferType);
+ if (sniffer != null) {
+ sniffers.add(sniffer);
+ } else {
+ logger.log(Level.SEVERE, KernelLoggerInfo.cantFindSniffer, snifferType);
+ }
+ }
+ if (sniffers.isEmpty()) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.cantFindSnifferForApp, app.getName());
+ return null;
+ }
+ } else {
+ // todo, this is a cludge to force the reload and reparsing of the
+ // composite application.
+ return null;
+ }
+
+ return sniffers;
+ }
+
+ private ExecutorService createExecutorService() {
+ Runtime runtime = Runtime.getRuntime();
+ int nrOfProcessors = runtime.availableProcessors();
+ return Executors.newFixedThreadPool(nrOfProcessors, new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r);
+ t.setName("deployment-jar-scanner");
+ t.setContextClassLoader(getClass().getClassLoader());
+ t.setDaemon(true);
+ return t;
+ }
+ });
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLoaderService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLoaderService.java
new file mode 100644
index 0000000..11ab077
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLoaderService.java
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.config.serverbeans.*;
+import com.sun.enterprise.deploy.shared.ArchiveFactory;
+import com.sun.enterprise.util.io.FileUtils;
+import com.sun.enterprise.v3.common.HTMLActionReporter;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.StartupRunLevel;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.deployment.DeployCommandParameters;
+import org.glassfish.api.deployment.DeploymentContext;
+import org.glassfish.api.deployment.UndeployCommandParameters;
+import org.glassfish.api.deployment.archive.ArchiveHandler;
+import org.glassfish.api.deployment.archive.ReadableArchive;
+import org.glassfish.api.event.EventListener.Event;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.deployment.common.ApplicationConfigInfo;
+import org.glassfish.deployment.common.DeploymentContextImpl;
+import org.glassfish.deployment.common.DeploymentUtils;
+import org.glassfish.deployment.common.InstalledLibrariesResolver;
+import org.glassfish.deployment.monitor.DeploymentLifecycleStatsProvider;
+import org.glassfish.external.probe.provider.PluginPoint;
+import org.glassfish.external.probe.provider.StatsProviderManager;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.glassfish.internal.data.ApplicationInfo;
+import org.glassfish.internal.data.ApplicationRegistry;
+import org.glassfish.internal.data.ContainerRegistry;
+import org.glassfish.internal.data.EngineInfo;
+import org.glassfish.internal.deployment.*;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.glassfish.security.services.impl.AuthenticationServiceImpl;
+import org.jvnet.hk2.annotations.Optional;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * This service is responsible for loading all deployed applications...
+ *
+ * @author Jerome Dochez
+ */
+//@Priority(8) // low priority , should be started last
+@Service(name="ApplicationLoaderService")
+@RunLevel( value=StartupRunLevel.VAL, mode=RunLevel.RUNLEVEL_MODE_NON_VALIDATING)
+public class ApplicationLoaderService implements org.glassfish.hk2.api.PreDestroy, org.glassfish.hk2.api.PostConstruct {
+//public class ApplicationLoaderService implements Startup, org.glassfish.hk2.api.PreDestroy, org.glassfish.hk2.api.PostConstruct {
+
+ final Logger logger = KernelLoggerInfo.getLogger();
+
+ // During the authentication service's PostConstruct the javax.security.auth.login.Configuration class is constructed.
+ // During the Configuration initialization a static variable is set to the current thread's context class loader.
+ // When applications are loaded via this (ApplicationLoaderService) the current thread's context class loader
+ // is temporarily set. When an application is loaded it will access the authentication service. If the
+ // authentication service gets initialized at this time then the Configuration construction will happen and its
+ // static variable will be set to the thread's temporarily set context class loader. Therefore by making
+ // a reference to the authentication service here we guarantee that it will be created before this
+ // (ApplicationLoaderService) service is created.
+ @Inject @Optional
+ private AuthenticationServiceImpl authenticationService;
+
+ @Inject
+ Deployment deployment;
+
+ @Inject
+ Provider<ArchiveFactory> archiveFactoryProvider;
+
+ @Inject
+ SnifferManager snifferManager;
+
+ @Inject
+ ContainerRegistry containerRegistry;
+
+ @Inject
+ ApplicationRegistry appRegistry;
+
+ @Inject
+ Events events;
+
+ @Inject
+ protected Applications applications;
+
+ protected SystemApplications systemApplications;
+
+ protected Domain domain;
+
+ @Inject @Named( ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Server server;
+
+ @Inject
+ ServerEnvironment env;
+
+ @Inject
+ ServiceLocator habitat;
+
+ private String deploymentTracingEnabled = null;
+
+ private Map<String,Integer> appOrderInfoMap = new HashMap<String, Integer>();
+ private int appOrder = 0;
+
+ /**
+ * Starts the application loader service.
+ *
+ * Look at the list of applications installed in our local repository
+ * Get a Deployer capable for each application found
+ * Invoke the deployer load() method for each application.
+ */
+ public void postConstruct() {
+
+ assert env!=null;
+ try{
+ logger.fine("Satisfying Optional Packages dependencies...");
+ InstalledLibrariesResolver.initializeInstalledLibRegistry(env.getLibPath().getAbsolutePath());
+ }catch(Exception e){
+ logger.log(Level.WARNING, KernelLoggerInfo.exceptionOptionalDepend, e);
+ }
+
+ DeploymentLifecycleStatsProvider dlsp = new DeploymentLifecycleStatsProvider();
+ StatsProviderManager.register("deployment", PluginPoint.SERVER,
+ "deployment/lifecycle", dlsp);
+
+ deploymentTracingEnabled = System.getProperty(
+ "org.glassfish.deployment.trace");
+
+ domain = habitat.getService(Domain.class);
+
+ /*
+ * Build a map that associates an application with its
+ * order in domain.xml. If the deployment-order attribute
+ * is not used for any application, then the applications
+ * are loaded in the order they occur in domain.xml. Also, for
+ * applications with the same deployment-order attribute,
+ * the applications are loaded in the order they occur in domain.xml.
+ * Otherwise, applications are loaded according to the
+ * deploynment-order attribute.
+ */
+ systemApplications = domain.getSystemApplications();
+ for (Application systemApp : systemApplications.getApplications()) {
+ appOrderInfoMap.put(systemApp.getName(), Integer.valueOf(appOrder++));
+ }
+ List<Application> standaloneAdapters =
+ applications.getApplicationsWithSnifferType(ServerTags.CONNECTOR, true);
+ for (Application standaloneAdapter : standaloneAdapters) {
+ appOrderInfoMap.put(standaloneAdapter.getName(), Integer.valueOf(appOrder++));
+ }
+ List<Application> allApplications = applications.getApplications();
+ for (Application app : allApplications) {
+ appOrderInfoMap.put(app.getName(), Integer.valueOf(appOrder++));
+ }
+
+ for (Application systemApp : systemApplications.getApplications()) {
+ // check to see if we need to load up this system application
+ if (Boolean.valueOf(systemApp.getDeployProperties().getProperty
+ (ServerTags.LOAD_SYSTEM_APP_ON_STARTUP))) {
+ if (deployment.isAppEnabled(systemApp) || loadAppOnDAS(systemApp.getName())) {
+ Integer order = appOrderInfoMap.get(systemApp.getName());
+ ApplicationOrderInfo info = new ApplicationOrderInfo(systemApp, order);
+ DeploymentOrder.addApplicationDeployment(info);
+ }
+ }
+ }
+
+ // load standalone resource adapters first
+ for (Application standaloneAdapter : standaloneAdapters) {
+ // load the referenced enabled applications on this instance
+ // and always (partially) load on DAS when application is
+ // referenced by non-DAS target so the application
+ // information is available on DAS
+ if (deployment.isAppEnabled(standaloneAdapter) || loadAppOnDAS(standaloneAdapter.getName())) {
+ DeploymentOrder.addApplicationDeployment(new ApplicationOrderInfo(standaloneAdapter, appOrderInfoMap.get(standaloneAdapter.getName()).intValue()));
+ }
+ }
+
+ // then the rest of the applications
+ for (Application app : allApplications) {
+ if (app.isStandaloneModule() &&
+ app.containsSnifferType(ServerTags.CONNECTOR)) {
+ continue;
+ }
+ // load the referenced enabled applications on this instance
+ // and always (partially) load on DAS when application is
+ // referenced by non-DAS target so the application
+ // information is available on DAS
+ if (deployment.isAppEnabled(app) || loadAppOnDAS(app.getName())) {
+ DeploymentOrder.addApplicationDeployment(new ApplicationOrderInfo(app, appOrderInfoMap.get(app.getName()).intValue()));
+ }
+ }
+
+ Iterator iter = DeploymentOrder.getApplicationDeployments();
+ while (iter.hasNext()) {
+ Application app = (Application)iter.next();
+ ApplicationRef appRef = server.getApplicationRef(app.getName());
+ processApplication(app, appRef);
+ }
+
+ // does the user want us to run a particular application
+ String defaultParam = env.getStartupContext().getArguments().getProperty("default");
+ if (defaultParam!=null) {
+
+ initializeRuntimeDependencies();
+
+ File sourceFile;
+ if (defaultParam.equals(".")) {
+ sourceFile = new File(System.getProperty("user.dir"));
+ } else {
+ sourceFile = new File(defaultParam);
+ }
+
+
+ if (sourceFile.exists()) {
+ sourceFile = sourceFile.getAbsoluteFile();
+ ReadableArchive sourceArchive=null;
+ try {
+ sourceArchive = archiveFactoryProvider.get().openArchive(sourceFile);
+
+ DeployCommandParameters parameters = new DeployCommandParameters(sourceFile);
+ parameters.name = sourceFile.getName();
+ parameters.enabled = Boolean.TRUE;
+ parameters.origin = DeployCommandParameters.Origin.deploy;
+
+ ActionReport report = new HTMLActionReporter();
+
+ if (!sourceFile.isDirectory()) {
+
+ // ok we need to explode the directory somwhere and remember to delete it on shutdown
+ final File tmpFile = File.createTempFile(sourceFile.getName(),"");
+ final String path = tmpFile.getAbsolutePath();
+ if (!tmpFile.delete()) {
+ logger.log(Level.WARNING, KernelLoggerInfo.cantDeleteTempFile, path);
+ }
+ File tmpDir = new File(path);
+ tmpDir.deleteOnExit();
+ events.register(new org.glassfish.api.event.EventListener() {
+ public void event(Event event) {
+ if (event.is(EventTypes.SERVER_SHUTDOWN)) {
+ if (tmpFile.exists()) {
+ FileUtils.whack(tmpFile);
+ }
+ }
+ }
+ });
+ if (tmpDir.mkdirs()) {
+ ArchiveHandler handler = deployment.getArchiveHandler(sourceArchive);
+ final String appName = handler.getDefaultApplicationName(sourceArchive);
+ DeploymentContextImpl dummyContext = new DeploymentContextImpl(report, logger, sourceArchive, parameters, env);
+ handler.expand(sourceArchive, archiveFactoryProvider.get().createArchive(tmpDir), dummyContext);
+ sourceArchive =
+ archiveFactoryProvider.get().openArchive(tmpDir);
+ logger.log(Level.INFO, KernelLoggerInfo.sourceNotDirectory, tmpDir.getAbsolutePath());
+ parameters.name = appName;
+ }
+ }
+ ExtendedDeploymentContext depContext = deployment.getBuilder(logger, parameters, report).source(sourceArchive).build();
+
+ ApplicationInfo appInfo = deployment.deploy(depContext);
+ if (appInfo==null) {
+
+ logger.log(Level.SEVERE, KernelLoggerInfo.cantFindApplicationInfo, sourceFile.getAbsolutePath());
+ }
+ } catch(RuntimeException e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.deployException, e);
+ } catch(IOException ioe) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.deployException, ioe);
+ } finally {
+ if (sourceArchive!=null) {
+ try {
+ sourceArchive.close();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+ }
+ }
+ }
+ events.send(new Event<DeploymentContext>(Deployment.ALL_APPLICATIONS_PROCESSED, null));
+
+ }
+
+ private void initializeRuntimeDependencies() {
+ // ApplicationLoaderService needs to be initialized after
+ // ManagedBeanManagerImpl. By injecting ManagedBeanManagerImpl,
+ // we guarantee the initialization order.
+ habitat.getAllServices(BuilderHelper.createNameFilter("ManagedBeanManagerImpl"));
+
+ // ApplicationLoaderService needs to be initialized after
+ // ResourceManager. By injecting ResourceManager, we guarantee the
+ // initialization order.
+ // See https://glassfish.dev.java.net/issues/show_bug.cgi?id=7179
+ habitat.getAllServices(BuilderHelper.createNameFilter("ResourceManager"));
+
+ // Application scoped resource is loaded after ResourceManager
+ // http://java.net/jira/browse/GLASSFISH-19161
+ habitat.getAllServices(BuilderHelper.createNameFilter("ApplicationScopedResourcesManager"));
+
+ }
+
+
+ public void processApplication(Application app, ApplicationRef appRef) {
+
+ long operationStartTime = Calendar.getInstance().getTimeInMillis();
+
+ initializeRuntimeDependencies();
+
+ String source = app.getLocation();
+ final String appName = app.getName();
+
+ // lifecycle modules are loaded separately
+ if (Boolean.valueOf(app.getDeployProperties().getProperty
+ (ServerTags.IS_LIFECYCLE))) {
+ return;
+ }
+
+ URI uri;
+ try {
+ uri = new URI(source);
+ } catch (URISyntaxException e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.cantDetermineLocation, e.getLocalizedMessage());
+ return;
+ }
+ File sourceFile = new File(uri);
+ if (sourceFile.exists()) {
+ try {
+ ReadableArchive archive = null;
+ try {
+
+ DeploymentTracing tracing = null;
+ if (deploymentTracingEnabled != null) {
+ tracing = new DeploymentTracing();
+ }
+ DeployCommandParameters deploymentParams =
+ app.getDeployParameters(appRef);
+ deploymentParams.target = server.getName();
+ deploymentParams.origin = DeployCommandParameters.Origin.load;
+ deploymentParams.command = DeployCommandParameters.Command.startup_server;
+ if (domain.isAppReferencedByPaaSTarget(appName)) {
+ if (server.isDas()) {
+ // for loading PaaS application on DAS
+ // we set it to the real PaaS target
+ deploymentParams.target = deployment.getDefaultTarget(appName, deploymentParams.origin, deploymentParams._classicstyle);
+ }
+ }
+
+ archive = archiveFactoryProvider.get().openArchive(sourceFile, deploymentParams);
+
+ ActionReport report = new HTMLActionReporter();
+ ExtendedDeploymentContext depContext = deployment.getBuilder(logger, deploymentParams, report).source(archive).build();
+ if (tracing!=null) {
+ depContext.addModuleMetaData(tracing);
+ }
+
+ depContext.getAppProps().putAll(app.getDeployProperties());
+ depContext.setModulePropsMap(app.getModulePropertiesMap());
+
+ new ApplicationConfigInfo(app).store(depContext.getAppProps());
+
+ deployment.deploy(deployment.getSniffersFromApp(app), depContext);
+ loadApplicationForTenants(app, appRef, report);
+ if (report.getActionExitCode().equals(ActionReport.ExitCode.SUCCESS)) {
+ if (tracing!=null) {
+ tracing.print(System.out);
+ }
+ logger.log(Level.INFO, KernelLoggerInfo.loadingApplicationTime, new Object[] {
+ appName, (Calendar.getInstance().getTimeInMillis() - operationStartTime)});
+ } else {
+ logger.log(Level.SEVERE, KernelLoggerInfo.deployFail, report.getMessage());
+ }
+ } finally {
+ if (archive!=null) {
+ try {
+ archive.close();
+ } catch(IOException e) {
+ logger.log(Level.FINE, KernelLoggerInfo.deployException, e);
+ }
+ }
+ }
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionOpenArtifact, e);
+
+ }
+
+ } else {
+ logger.log(Level.SEVERE, KernelLoggerInfo.notFoundInOriginalLocation, source);
+ }
+ }
+
+
+ public String toString() {
+ return "Application Loader";
+ }
+
+ /**
+ * Stopped all loaded applications
+ */
+ public void preDestroy() {
+
+
+ // stop all running applications including user and system applications
+ // which are registered in the domain.xml
+ List<Application> allApplications = new ArrayList<Application>();
+
+ List<Application> standaloneAdapters =
+ applications.getApplicationsWithSnifferType(ServerTags.CONNECTOR, true);
+
+ allApplications.addAll(applications.getApplications());
+ allApplications.addAll(systemApplications.getApplications());
+
+ //stop applications that are not of type "standalone" connectors
+ for (Application app : allApplications) {
+ if (app.isStandaloneModule() &&
+ app.containsSnifferType(ServerTags.CONNECTOR)) {
+ continue;
+ }
+ ApplicationInfo appInfo = deployment.get(app.getName());
+ stopApplication(app, appInfo);
+ }
+
+ //stop applications that are "standalone" connectors
+ for (Application app : standaloneAdapters) {
+ ApplicationInfo appInfo = deployment.get(app.getName());
+ stopApplication(app, appInfo);
+ }
+
+ // now stop the applications which are not registered in the
+ // domain.xml like timer service application
+ Set<String> allAppNames = new HashSet<String>();
+ allAppNames.addAll(appRegistry.getAllApplicationNames());
+ for (String appName : allAppNames) {
+ ApplicationInfo appInfo = appRegistry.get(appName);
+ stopApplication(null, appInfo);
+ }
+
+ // stop all the containers
+ for (EngineInfo engineInfo : containerRegistry.getContainers()) {
+ engineInfo.stop(logger);
+ }
+ }
+
+ private void stopApplication(Application app, ApplicationInfo appInfo) {
+ final ActionReport dummy = new HTMLActionReporter();
+ if (appInfo!=null) {
+ UndeployCommandParameters parameters = new UndeployCommandParameters(appInfo.getName());
+ parameters.origin = UndeployCommandParameters.Origin.unload;
+ parameters.command = UndeployCommandParameters.Command.shutdown_server;
+
+ try {
+ deployment.disable(parameters, app, appInfo, dummy, logger);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.loadingApplicationErrorDisable, e);
+ }
+ unloadApplicationForTenants(app, dummy);
+ appRegistry.remove(appInfo.getName());
+ }
+ }
+
+ private void unloadApplicationForTenants(Application app, ActionReport report) {
+ if (app == null || app.getAppTenants() == null) {
+ return;
+ }
+
+ for (AppTenant tenant : app.getAppTenants().getAppTenant()) {
+ UndeployCommandParameters parameters = new UndeployCommandParameters();
+ parameters.name = DeploymentUtils.getInternalNameForTenant(app.getName(), tenant.getTenant());
+ parameters.origin = UndeployCommandParameters.Origin.unload;
+ parameters.target = server.getName();
+ ApplicationInfo appInfo = deployment.get(parameters.name);
+ if (appInfo == null) {
+ continue;
+ }
+
+ ActionReport subReport = report.addSubActionsReport();
+
+ try {
+ ExtendedDeploymentContext deploymentContext = deployment.getBuilder(KernelLoggerInfo.getLogger(), parameters, subReport).source(appInfo.getSource()).build();
+
+ deploymentContext.getAppProps().putAll(
+ app.getDeployProperties());
+ deploymentContext.getAppProps().putAll(
+ tenant.getDeployProperties());
+ deploymentContext.setModulePropsMap(
+ app.getModulePropertiesMap());
+
+ deploymentContext.setTenant(tenant.getTenant(), app.getName());
+
+ deployment.unload(appInfo, deploymentContext);
+
+ } catch(Throwable e) {
+ subReport.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ subReport.setMessage(e.getMessage());
+ subReport.setFailureCause(e);
+ }
+ appRegistry.remove(appInfo.getName());
+ }
+ }
+
+ private void loadApplicationForTenants(Application app, ApplicationRef appRef, ActionReport report) {
+ if (app.getAppTenants() == null) {
+ return;
+ }
+ for (AppTenant tenant : app.getAppTenants().getAppTenant()) {
+ DeployCommandParameters commandParams = app.getDeployParameters(appRef);
+ commandParams.contextroot = tenant.getContextRoot();
+ commandParams.target = server.getName();
+ commandParams.name = DeploymentUtils.getInternalNameForTenant(app.getName(), tenant.getTenant());
+ commandParams.enabled = Boolean.TRUE;
+ commandParams.origin = DeployCommandParameters.Origin.load;
+
+ ActionReport subReport = report.addSubActionsReport();
+ ReadableArchive archive = null;
+
+ try {
+ URI uri = new URI(app.getLocation());
+ File file = new File(uri);
+
+ if (file.exists()) {
+ archive = archiveFactoryProvider.get().openArchive(file);
+
+ ExtendedDeploymentContext deploymentContext =
+ deployment.getBuilder(KernelLoggerInfo.getLogger(), commandParams, subReport).source(archive).build();
+
+ deploymentContext.getAppProps().putAll(app.getDeployProperties());
+ deploymentContext.getAppProps().putAll(tenant.getDeployProperties());
+ deploymentContext.setModulePropsMap(app.getModulePropertiesMap());
+ deploymentContext.setTenant(tenant.getTenant(), app.getName());
+ deployment.deploy(deployment.getSniffersFromApp(app), deploymentContext);
+ } else {
+ logger.log(Level.SEVERE, KernelLoggerInfo.notFoundInOriginalLocation, app.getLocation());
+ }
+ } catch(Throwable e) {
+ subReport.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ subReport.setMessage(e.getMessage());
+ subReport.setFailureCause(e);
+ } finally {
+ try {
+ if (archive != null) {
+ archive.close();
+ }
+ } catch(IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ private boolean loadAppOnDAS(String appName) {
+ if (server.isDas()) {
+ List<String> targets = domain.getAllReferencedTargetsForApplication(appName);
+ for (String target : targets) {
+ if (!DeploymentUtils.isDASTarget(target)) {
+ // if application is referenced by any non-DAS target
+ // we need to partially load it on DAS
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ClassLoaderHierarchyImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ClassLoaderHierarchyImpl.java
new file mode 100644
index 0000000..4263272
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ClassLoaderHierarchyImpl.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import org.glassfish.internal.api.ClassLoaderHierarchy;
+import javax.inject.Inject;
+
+import org.jvnet.hk2.annotations.Optional;
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.jvnet.hk2.config.TranslationException;
+import org.jvnet.hk2.config.VariableResolver;
+import org.glassfish.internal.api.DelegatingClassLoader;
+import org.glassfish.internal.api.ConnectorClassLoaderService;
+import org.glassfish.api.deployment.archive.ReadableArchive;
+import org.glassfish.api.deployment.DeploymentContext;
+
+import java.net.URI;
+import java.net.MalformedURLException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.jar.Manifest;
+import java.io.File;
+import java.io.IOException;
+
+import com.sun.enterprise.module.*;
+import com.sun.enterprise.module.common_impl.DirectoryBasedRepository;
+import com.sun.enterprise.module.common_impl.Tokenizer;
+
+
+/**
+ * @author Sanjeeb.Sahoo@Sun.COM
+ */
+@Service
+public class ClassLoaderHierarchyImpl implements ClassLoaderHierarchy {
+ @Inject APIClassLoaderServiceImpl apiCLS;
+
+ @Inject CommonClassLoaderServiceImpl commonCLS;
+
+ //For distributions where connector module is not available.
+ @Inject @Optional ConnectorClassLoaderService connectorCLS;
+
+ @Inject
+ AppLibClassLoaderServiceImpl applibCLS;
+
+ @Inject
+ ModulesRegistry modulesRegistry;
+
+ @Inject
+ Logger logger;
+
+ @Inject
+ ServiceLocator habitat;
+
+ SystemVariableResolver resolver = new SystemVariableResolver();
+
+ public ClassLoader getAPIClassLoader() {
+ return apiCLS.getAPIClassLoader();
+ }
+
+ public ClassLoader getCommonClassLoader() {
+ return commonCLS.getCommonClassLoader();
+ }
+
+ public String getCommonClassPath() {
+ return commonCLS.getCommonClassPath();
+ }
+
+ public DelegatingClassLoader getConnectorClassLoader(String application) {
+ // For distributions where connector module (connector CL) is not available, use empty classloader with parent
+ if(connectorCLS != null){
+ return connectorCLS.getConnectorClassLoader(application);
+ }else{
+ return AccessController.doPrivileged(new PrivilegedAction<DelegatingClassLoader>() {
+ public DelegatingClassLoader run() {
+ return new DelegatingClassLoader(commonCLS.getCommonClassLoader());
+ }
+ });
+ }
+ }
+
+ public ClassLoader getAppLibClassLoader(String application, List<URI> libURIs) throws MalformedURLException {
+ return applibCLS.getAppLibClassLoader(application, libURIs);
+ }
+
+ public DelegatingClassLoader.ClassFinder getAppLibClassFinder(List<URI> libURIs) throws MalformedURLException {
+ return applibCLS.getAppLibClassFinder(libURIs);
+ }
+
+ /**
+ * Sets up the parent class loader for the application class loader.
+ * Application class loader are under the control of the ArchiveHandler since
+ * a special archive file format will require a specific class loader.
+ *
+ * However GlassFish needs to be able to add capabilities to the application
+ * like adding APIs accessibility, this is done through its parent class loader
+ * which we create and maintain.
+ *
+ * @param parent the parent class loader
+ * @param context deployment context
+ * @return class loader capable of loading public APIs identified by the deployers
+ * @throws ResolveError if one of the deployer's public API module is not found.
+ */
+ public ClassLoader createApplicationParentCL(ClassLoader parent, DeploymentContext context)
+ throws ResolveError {
+
+ final ReadableArchive source = context.getSource();
+ List<ModuleDefinition> defs = new ArrayList<ModuleDefinition>();
+
+ // now let's see if the application is requesting any module imports
+ Manifest m=null;
+ try {
+ m = source.getManifest();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Cannot load application's manifest file :", e.getMessage());
+ if (logger.isLoggable(Level.FINE)) {
+ logger.log(Level.FINE, e.getMessage(), e);
+ }
+ }
+ if (m!=null) {
+ String importedBundles = m.getMainAttributes().getValue(ManifestConstants.BUNDLE_IMPORT_NAME);
+ if (importedBundles!=null) {
+ for( String token : new Tokenizer(importedBundles,",")) {
+ Collection<Module> modules = modulesRegistry.getModules(token);
+ if (modules.size() ==1) {
+ defs.add(modules.iterator().next().getModuleDefinition());
+ } else {
+ throw new ResolveError("Not able to locate a unique module by name " + token);
+ }
+ }
+ }
+
+ // Applications can add an additional osgi repos...
+ String additionalRepo = m.getMainAttributes().getValue(org.glassfish.api.ManifestConstants.GLASSFISH_REQUIRE_REPOSITORY);
+ if (additionalRepo != null) {
+ for (String token : new Tokenizer(additionalRepo, ",")) {
+ // Each entry should be name=path
+ int equals = token.indexOf('=');
+ if (equals == -1) {
+ // Missing '='...
+ throw new IllegalArgumentException("\""
+ + org.glassfish.api.ManifestConstants.GLASSFISH_REQUIRE_REPOSITORY
+ + ": " + additionalRepo + "\" is missing an '='. "
+ + "It must be in the format: name=path[,name=path]...");
+ }
+ String name = token.substring(0, equals);
+ String path = token.substring(++equals);
+ addRepository(name, resolver.translate(path));
+ }
+ }
+
+ // Applications can also request to be wired to implementors of certain services.
+ // That means that any module implementing the requested service will be accessible
+ // by the parent class loader of the application.
+ String requestedWiring = m.getMainAttributes().getValue(org.glassfish.api.ManifestConstants.GLASSFISH_REQUIRE_SERVICES);
+ if (requestedWiring!=null) {
+ for (String token : new Tokenizer(requestedWiring, ",")) {
+ for (Object impl : habitat.getAllServices(BuilderHelper.createContractFilter(token))) {
+ Module wiredBundle = modulesRegistry.find(impl.getClass());
+ if (wiredBundle!=null) {
+ defs.add(wiredBundle.getModuleDefinition());
+ }
+ }
+ }
+ }
+ }
+
+ if (defs.isEmpty()) {
+ return parent;
+ } else {
+ return modulesRegistry.getModulesClassLoader(parent, defs);
+ }
+ }
+
+ /**
+ * <p> This method installs the admin console OSGi bundle respository so
+ * our plugins can be found.</p>
+ */
+ private void addRepository(String name, String path) {
+ File pathFile = new File(path);
+ Repository repo = new DirectoryBasedRepository(
+ name, pathFile);
+ modulesRegistry.addRepository(repo);
+ try {
+ repo.initialize();
+ } catch (IOException ex) {
+ logger.log(Level.SEVERE,
+ "Problem initializing additional repository!", ex);
+ }
+ }
+
+ /**
+ * <p> This class helps resolve ${} variables in Strings.</p>
+ */
+ private static class SystemVariableResolver extends VariableResolver {
+ SystemVariableResolver() {
+ super();
+ }
+
+ protected String getVariableValue(final String varName) throws TranslationException {
+ String result = null;
+
+ // first look for a system property
+ final Object value = System.getProperty(varName);
+ if (value != null) {
+ result = "" + value;
+ } else {
+ result = "${" + varName + "}";
+ }
+ return result;
+ }
+
+ /**
+ Return true if the string is a template string of the for ${...}
+ */
+ public static boolean needsResolving(final String value) {
+ return (value != null) && (value.indexOf("${") != -1);
+ }
+
+ /**
+ * Resolve the given String.
+ */
+ public String resolve(final String value) throws TranslationException {
+ final String result = translate(value);
+ return result;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/CommonClassLoaderServiceImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/CommonClassLoaderServiceImpl.java
new file mode 100644
index 0000000..ed7f318
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/CommonClassLoaderServiceImpl.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * This class is responsible for setting up Common Class Loader. As the
+ * name suggests, Common Class Loader is common to all deployed applications.
+ * Common Class Loader is responsible for loading classes from
+ * following URLs (the order is strictly maintained):
+ * lib/*.jar:domain_dir/lib/classes:domain_dir/lib/*.jar:DERBY_DRIVERS.
+ * Please note that domain_dir/lib/classes comes before domain_dir/lib/*.jar,
+ * just like WEB-INF/classes is searched first before WEB-INF/lib/*.jar.
+ * DERBY_DRIVERS are added to this class loader, because GlassFish ships with Derby database by default
+ * and it makes them available to users by default. Earlier, they used to be available to applications via
+ * launcher classloader, but now they are available via this class loader (see issue 13612 for more details on this).
+ *
+ * It applies a special rule while handling jars in install_root/lib.
+ * In order to maintain file layout compatibility (see issue #9526),
+ * we add jars like javaee.jar and appserv-rt.jar which need to be excluded
+ * from runtime classloaders in the server side, as they are already available via
+ * PublicAPIClassLoader. So, before we add any jar from install_root/lib,
+ * we look at their manifest entry and skip the ones that have an entry
+ * GlassFish-ServerExcluded: true
+ *
+ * @author Sanjeeb.Sahoo@Sun.COM
+ */
+@Service
+public class CommonClassLoaderServiceImpl implements PostConstruct {
+ /**
+ * The common classloader.
+ */
+ private ClassLoader commonClassLoader;
+
+ @Inject
+ APIClassLoaderServiceImpl acls;
+
+ @Inject
+ ServerEnvironment env;
+
+ final static Logger logger = KernelLoggerInfo.getLogger();
+ private ClassLoader APIClassLoader;
+ private String commonClassPath = "";
+
+ private static final String SERVER_EXCLUDED_ATTR_NAME = "GlassFish-ServerExcluded";
+
+ public void postConstruct() {
+ APIClassLoader = acls.getAPIClassLoader();
+ assert (APIClassLoader != null);
+ createCommonClassLoader();
+ }
+
+ private void createCommonClassLoader() {
+ List<File> cpElements = new ArrayList<File>();
+ File domainDir = env.getDomainRoot();
+ // I am forced to use System.getProperty, as there is no API that makes
+ // the installRoot available. Sad, but true. Check dev forum on this.
+ final String installRoot = System.getProperty(
+ SystemPropertyConstants.INSTALL_ROOT_PROPERTY);
+
+ // See https://glassfish.dev.java.net/issues/show_bug.cgi?id=5872
+ // In case of embedded GF, we may not have an installRoot.
+ if (installRoot!=null) {
+ File installDir = new File(installRoot);
+ File installLibPath = new File(installDir, "lib");
+ if (installLibPath.isDirectory()) {
+ Collections.addAll(cpElements,
+ installLibPath.listFiles(new CompiletimeJarFileFilter()));
+ }
+ } else {
+ logger.logp(Level.WARNING, "CommonClassLoaderServiceImpl",
+ "createCommonClassLoader",
+ KernelLoggerInfo.systemPropertyNull,
+ SystemPropertyConstants.INSTALL_ROOT_PROPERTY);
+ }
+ File domainClassesDir = new File(domainDir, "lib/classes/"); // NOI18N
+ if (domainClassesDir.exists()) {
+ cpElements.add(domainClassesDir);
+ }
+ final File domainLib = new File(domainDir, "lib/"); // NOI18N
+ if (domainLib.isDirectory()) {
+ Collections.addAll(cpElements,
+ domainLib.listFiles(new JarFileFilter()));
+ }
+ // See issue https://glassfish.dev.java.net/issues/show_bug.cgi?id=13612
+ // We no longer add derby jars to launcher class loader, we add them to common class loader instead.
+ cpElements.addAll(findDerbyClient());
+ List<URL> urls = new ArrayList<URL>();
+ StringBuilder cp = new StringBuilder();
+ for (File f : cpElements) {
+ try {
+ urls.add(f.toURI().toURL());
+ if (cp.length() > 0) {
+ cp.append(File.pathSeparator);
+ }
+ cp.append(f.getAbsolutePath());
+ } catch (MalformedURLException e) {
+ logger.log(Level.WARNING, KernelLoggerInfo.invalidClassPathEntry,
+ new Object[] {f, e});
+ }
+ }
+ commonClassPath = cp.toString();
+ if (!urls.isEmpty()) {
+ // Skip creation of an unnecessary classloader in the hierarchy,
+ // when all it would have done was to delegate up.
+ commonClassLoader = new URLClassLoader(
+ urls.toArray(new URL[urls.size()]), APIClassLoader);
+ } else {
+ logger.logp(Level.FINE, "CommonClassLoaderManager",
+ "Skipping creation of CommonClassLoader " +
+ "as there are no libraries available",
+ "urls = {0}", new Object[]{urls});
+ }
+ }
+
+ public ClassLoader getCommonClassLoader() {
+ return commonClassLoader != null ? commonClassLoader : APIClassLoader;
+ }
+
+ public String getCommonClassPath() {
+ return commonClassPath;
+ }
+
+ private List<File> findDerbyClient() {
+ final String DERBY_HOME_PROP = "AS_DERBY_INSTALL";
+ StartupContext startupContext = env.getStartupContext();
+ Properties arguments = null;
+
+ if (startupContext != null) {
+ arguments = startupContext.getArguments();
+ }
+
+ String derbyHome = null;
+
+ if (arguments != null) {
+ derbyHome = arguments.getProperty(DERBY_HOME_PROP,
+ System.getProperty(DERBY_HOME_PROP));
+ }
+
+ File derbyLib = null;
+ if (derbyHome != null) {
+ derbyLib = new File(derbyHome, "lib");
+ }
+ if (derbyLib == null || !derbyLib.exists()) {
+ // maybe the jdk...
+ if (System.getProperty("java.version").compareTo("1.6") > 0) {
+ File jdkHome = new File(System.getProperty("java.home"));
+ derbyLib = new File(jdkHome, "../db/lib");
+ }
+ }
+ if (!derbyLib.exists()) {
+ logger.info(KernelLoggerInfo.cantFindDerby);
+ return Collections.EMPTY_LIST;
+ }
+
+ return Arrays.asList(derbyLib.listFiles(new FilenameFilter(){
+ public boolean accept(File dir, String name) {
+ // Include only files having .jar extn and exclude all localisation jars, because they are
+ // already mentioned in the Class-Path header of the main jars
+ return (name.endsWith(".jar") && !name.startsWith("derbyLocale_"));
+ }
+ }));
+ }
+
+ private static class JarFileFilter implements FilenameFilter {
+ private final String JAR_EXT = ".jar"; // NOI18N
+
+ public boolean accept(File dir, String name) {
+ return name.endsWith(JAR_EXT);
+ }
+ }
+
+ private static class CompiletimeJarFileFilter extends JarFileFilter {
+ /*
+ * See https://glassfish.dev.java.net/issues/show_bug.cgi?id=9526
+ */
+ @Override
+ public boolean accept(File dir, String name)
+ {
+ if (super.accept(dir, name)) {
+ File file = new File(dir, name);
+ JarFile jar = null;
+ try
+ {
+ jar = new JarFile(file);
+ Manifest manifest = jar.getManifest();
+ if (manifest != null) {
+ String exclude = manifest.getMainAttributes().
+ getValue(SERVER_EXCLUDED_ATTR_NAME);
+ if (exclude != null && exclude.equalsIgnoreCase("true")) {
+ return false;
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ logger.log(Level.WARNING, KernelLoggerInfo.exceptionProcessingJAR,
+ new Object[] {file.getAbsolutePath(), e});
+ } finally {
+ try
+ {
+ if (jar != null) jar.close();
+ }
+ catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/CompositeArchive.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/CompositeArchive.java
new file mode 100644
index 0000000..3826b6b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/CompositeArchive.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import org.glassfish.api.deployment.archive.ReadableArchive;
+import org.glassfish.api.deployment.archive.CompositeHandler;
+import com.sun.enterprise.deploy.shared.AbstractReadableArchive;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.util.*;
+import java.util.jar.Manifest;
+
+/**
+ * A composite archive is a readable archive that hides the sub archives.
+ *
+ * @author Jerome Dochez
+ */
+public class CompositeArchive extends AbstractReadableArchive {
+
+ final ReadableArchive delegate;
+ final CompositeHandler filter;
+
+ public CompositeArchive(ReadableArchive delegate, CompositeHandler filter) {
+ this.delegate = delegate;
+ this.filter = filter;
+ }
+
+ public InputStream getEntry(String name) throws IOException {
+ if (filter.accept(delegate, name)) {
+ return delegate.getEntry(name);
+ }
+ return null;
+ }
+
+ public boolean exists(String name) throws IOException {
+ if (filter.accept(delegate, name)) {
+ return delegate.exists(name);
+ }
+ return false;
+ }
+
+ public long getEntrySize(String name) {
+ if (filter.accept(delegate, name)) {
+ return delegate.getEntrySize(name);
+ }
+ return 0;
+ }
+
+ public void open(URI uri) throws IOException {
+ delegate.open(uri);
+ }
+
+ public ReadableArchive getSubArchive(String name) throws IOException {
+ if (filter.accept(delegate, name)) {
+ return delegate.getSubArchive(name);
+ }
+ return null;
+ }
+
+ public boolean exists() {
+ return delegate.exists();
+ }
+
+ public boolean delete() {
+ return delegate.delete();
+ }
+
+ public boolean renameTo(String name) {
+ return delegate.renameTo(name);
+ }
+
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ public Enumeration<String> entries() {
+
+ Enumeration<String> original = delegate.entries();
+ Vector<String> results = new Vector<String>();
+ while (original.hasMoreElements()) {
+ String entryName = original.nextElement();
+ if (filter.accept(delegate, entryName)) {
+ results.add(entryName);
+ }
+ }
+ return results.elements();
+ }
+
+ public Enumeration<String> entries(String prefix) {
+
+ Enumeration<String> original = delegate.entries(prefix);
+ Vector<String> results = new Vector<String>();
+ while (original.hasMoreElements()) {
+ String entryName = original.nextElement();
+ if (filter.accept(delegate, entryName)) {
+ results.add(entryName);
+ }
+ }
+ return results.elements();
+ }
+
+ public boolean isDirectory(String name) {
+ if (filter.accept(delegate, name)) {
+ return delegate.isDirectory(name);
+ }
+ return false;
+ }
+
+ public Manifest getManifest() throws IOException {
+ return delegate.getManifest();
+ }
+
+ public URI getURI() {
+ return delegate.getURI();
+ }
+
+ public long getArchiveSize() throws SecurityException {
+ return delegate.getArchiveSize();
+ }
+
+ public String getName() {
+ return delegate.getName();
+ }
+
+ // we don't hide the top level directories as we need to use them
+ // to figure out whether the EarSniffer can handle it in the
+ // case of optional application.xml
+ public Collection<String> getDirectories() throws IOException {
+ return delegate.getDirectories();
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ContainerStarter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ContainerStarter.java
new file mode 100644
index 0000000..da3f150
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ContainerStarter.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+
+import org.glassfish.api.container.Container;
+import org.glassfish.api.container.Sniffer;
+import org.glassfish.hk2.api.ServiceHandle;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.data.ContainerRegistry;
+import org.glassfish.internal.data.EngineInfo;
+import org.glassfish.server.ServerEnvironmentImpl;
+import org.jvnet.hk2.annotations.Service;
+
+import com.sun.enterprise.module.Module;
+
+/**
+ * This class is responsible for starting containers.
+ *
+ * @author Jerome Dochez, Sanjeeb Sahoo
+ */
+@Service
+public class ContainerStarter {
+
+ @Inject
+ ServiceLocator serviceLocator;
+
+ @Inject
+ ServiceLocator habitat;
+
+ @Inject
+ Logger logger;
+
+ @Inject
+ ServerEnvironmentImpl env;
+
+ @Inject ContainerRegistry registry;
+
+ public Collection<EngineInfo> startContainer(Sniffer sniffer) {
+
+ assert sniffer!=null;
+ String containerName = sniffer.getModuleType();
+ assert containerName!=null;
+
+ // I do the container setup first so the code has a chance to set up
+ // repositories which would allow access to the container module.
+ try {
+
+ Module[] modules = sniffer.setup(null, logger);
+ logger.logp(Level.FINE, "ContainerStarter", "startContainer", "Sniffer {0} set up following modules: {1}",
+ new Object[]{sniffer, modules != null ? Arrays.toString(modules): ""});
+ } catch(FileNotFoundException fnf) {
+ logger.log(Level.SEVERE, fnf.getMessage());
+ return null;
+ } catch(IOException ioe) {
+ logger.log(Level.SEVERE, ioe.getMessage(), ioe);
+ return null;
+
+ }
+
+ // first the right container from that module.
+ Map<String, EngineInfo> containers = new HashMap<String, EngineInfo>();
+ for (String name : sniffer.getContainersNames()) {
+ ServiceHandle<Container> provider = serviceLocator.getServiceHandle(Container.class, name);
+ if (provider == null) {
+ logger.severe("Cannot find Container named " + name + ", so unable to start " + sniffer.getModuleType() + " container");
+ return null;
+ }
+ EngineInfo info = new EngineInfo(provider, sniffer, null /* never used */);
+ containers.put(name, info);
+ }
+ // Now that we have successfully created all containers, let's register them as well.
+ for (Map.Entry<String, EngineInfo> entry : containers.entrySet()) {
+ registry.addContainer(entry.getKey(), entry.getValue());
+ }
+ return containers.values();
+ }
+
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DomainCreationStartup.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DomainCreationStartup.java
new file mode 100644
index 0000000..4f2e368
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DomainCreationStartup.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.module.bootstrap.*;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.server.ServerEnvironmentImpl;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Inject;
+import java.util.logging.Logger;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: dochez
+ * Date: Sep 18, 2009
+ * Time: 10:46:34 PM
+ * To change this template use File | Settings | File Templates.
+ */
+@Service(name = "DomainCreation")
+public class DomainCreationStartup implements ModuleStartup {
+
+ @Inject
+ Events events;
+
+ @Inject
+ ServerEnvironmentImpl env;
+
+ public void setStartupContext(StartupContext startupContext) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void start() {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void stop() {
+ try {
+ env.setStatus(ServerEnvironment.Status.stopped);
+ events.send(new EventListener.Event(EventTypes.SERVER_SHUTDOWN), false);
+ } catch (Exception ex) {
+ Logger.getAnonymousLogger().warning(ex.getMessage());
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DomainResolver.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DomainResolver.java
new file mode 100644
index 0000000..aac2336
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DomainResolver.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+
+import com.sun.enterprise.module.common_impl.LogHelper;
+
+import java.io.File;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.logging.Level;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+/**
+ * DTD resolver used when parsing the domain.xml and resolve to local DTD copies
+ *
+ * @author Jerome Dochez
+ * @Deprecated
+ */
+
+@Deprecated
+public class DomainResolver implements EntityResolver {
+ public InputSource resolveEntity(String publicId, String systemId) {
+
+ if (systemId.startsWith("http://www.sun.com/software/appserver/")) {
+ // return a special input source
+ String fileName = systemId.substring("http://www.sun.com/software/appserver/".length());
+ File f = new File(System.getProperty("com.sun.aas.installRoot"));
+ f = new File(f, "lib");
+ f = new File(f, fileName.replace('/', File.separatorChar));
+ if (f.exists()) {
+ try {
+ return new InputSource(new BufferedInputStream(new FileInputStream(f)));
+ } catch(IOException e) {
+ LogHelper.getDefaultLogger().log(Level.SEVERE, "Exception while getting " + fileName + " : ", e);
+ return null;
+ }
+ } else {
+ System.out.println("Cannot find " + f.getAbsolutePath());
+ return null;
+ }
+ //MyReader reader = new MyReader();
+ //return new InputSource(reader);
+ } else {
+ // use the default behaviour
+ return null;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DomainXmlPersistence.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DomainXmlPersistence.java
new file mode 100644
index 0000000..940f198
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DomainXmlPersistence.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.config.modularity.ConfigModularityUtils;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.util.io.FileUtils;
+import java.io.*;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.Lock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.glassfish.common.util.admin.ManagedFile;
+import org.glassfish.config.support.ConfigurationAccess;
+import org.glassfish.config.support.ConfigurationPersistence;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.internal.api.PostStartupRunLevel;
+import org.glassfish.server.ServerEnvironmentImpl;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.DomDocument;
+import org.jvnet.hk2.config.IndentingXMLStreamWriter;
+
+/**
+ * domain.xml persistence.
+ *
+ * @author Jerome Dochez
+ */
+@Service
+@Singleton
+public class DomainXmlPersistence implements ConfigurationPersistence, ConfigurationAccess {
+
+ @Inject
+ ServerEnvironmentImpl env;
+ @Inject
+ protected Logger logger;
+ @Inject
+ ConfigModularityUtils modularityUtils;
+
+ DomDocument skippedDoc = null;
+
+ final XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
+
+ final static LocalStringManagerImpl localStrings =
+ new LocalStringManagerImpl(DomainXmlPersistence.class);
+
+
+ private synchronized ManagedFile getPidFile() throws IOException {
+ File location=null;
+ try {
+ // I am locking indefinitely with a 2 seconds timeOut.
+ location = new File(env.getConfigDirPath(), "lockfile");
+ if (!location.exists()) {
+ if (!location.createNewFile()) {
+ if (!location.exists()) {
+ String message = localStrings.getLocalString("cannotCreateLockfile",
+ "Cannot create lock file at {0}, configuration changes will not be persisted",
+ location);
+ logger.log(Level.SEVERE, message);
+ throw new IOException(message);
+ }
+ }
+ }
+ return new ManagedFile(location, 2000, -1);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE,
+ localStrings.getLocalString("InvalidLocation",
+ "Cannot obtain lockfile location {0}, configuration changes will not be persisted",
+ location), e);
+ throw e;
+ }
+ }
+
+ @Override
+ public Lock accessRead() throws IOException, TimeoutException {
+ return getPidFile().accessRead();
+ }
+
+ @Override
+ public Lock accessWrite() throws IOException, TimeoutException {
+ return getPidFile().accessWrite();
+ }
+
+ @Override
+ public void save(DomDocument doc) throws IOException {
+ if (modularityUtils.isIgnorePersisting() && !modularityUtils.isCommandInvocation()) {
+ if (skippedDoc != null) {
+ assert(doc == skippedDoc);
+ }
+ skippedDoc = doc;
+ return;
+ }
+ File destination = getDestination();
+ if (destination == null) {
+ String msg = localStrings.getLocalString("NoLocation",
+ "domain.xml cannot be persisted, null destination");
+ logger.severe(msg);
+ throw new IOException(msg);
+ }
+ Lock writeLock=null;
+ try {
+ try {
+ writeLock = accessWrite();
+ } catch (TimeoutException e) {
+ String msg = localStrings.getLocalString("Timeout",
+ "Timed out when waiting for write lock on configuration file");
+ logger.log(Level.SEVERE, msg);
+ throw new IOException(msg, e);
+
+ }
+
+ // get a temporary file
+ File f = File.createTempFile("domain", ".xml", destination.getParentFile());
+ if (!f.exists()) {
+ throw new IOException(localStrings.getLocalString("NoTmpFile",
+ "Cannot create temporary file when saving domain.xml"));
+ }
+ // write to the temporary file
+ XMLStreamWriter writer = null;
+ OutputStream fos = getOutputStream(f);
+ try {
+ writer = xmlFactory.createXMLStreamWriter(new BufferedOutputStream(fos));
+ IndentingXMLStreamWriter indentingXMLStreamWriter = new IndentingXMLStreamWriter(writer);
+ doc.writeTo(indentingXMLStreamWriter);
+ indentingXMLStreamWriter.close();
+ }
+ catch (XMLStreamException e) {
+ String msg = localStrings.getLocalString("TmpFileNotSaved",
+ "Configuration could not be saved to temporary file");
+ logger.log(Level.SEVERE, msg, e);
+ throw new IOException(e.getMessage(), e);
+ // return after calling finally clause, because since temp file couldn't be saved,
+ // renaming should not be attempted
+ }
+ finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ }
+ catch (XMLStreamException e) {
+ logger.log(Level.SEVERE, localStrings.getLocalString("CloseFailed",
+ "Cannot close configuration writer stream"), e);
+ throw new IOException(e.getMessage(), e);
+ }
+ }
+ fos.close();
+ }
+
+ // backup the current file
+ File backup = new File(env.getConfigDirPath(), "domain.xml.bak");
+ if (destination.exists() && backup.exists() && !backup.delete()) {
+ String msg = localStrings.getLocalString("BackupDeleteFailed",
+ "Could not delete previous backup file at {0}" , backup.getAbsolutePath());
+ logger.severe(msg);
+ throw new IOException(msg);
+ }
+ if (destination.exists() && !FileUtils.renameFile(destination, backup)) {
+ String msg = localStrings.getLocalString("TmpRenameFailed",
+ "Could not rename {0} to {1}", destination.getAbsolutePath() , backup.getAbsolutePath());
+ logger.severe(msg);
+ throw new IOException(msg);
+ }
+ // save the temp file to domain.xml
+ if (!FileUtils.renameFile(f, destination)) {
+ String msg = localStrings.getLocalString("TmpRenameFailed",
+ "Could not rename {0} to {1}", f.getAbsolutePath() , destination.getAbsolutePath());
+ // try to rename backup to domain.xml (so that at least something is there)
+ if (!FileUtils.renameFile(backup, destination)) {
+ msg += "\n" + localStrings.getLocalString("RenameFailed",
+ "Could not rename backup to {0}", destination.getAbsolutePath());
+ }
+ logger.severe(msg);
+ throw new IOException(msg);
+ }
+ } catch(IOException e) {
+ logger.log(Level.SEVERE, localStrings.getLocalString("ioexception",
+ "IOException while saving the configuration, changes not persisted"), e);
+ throw e;
+ } finally {
+ if (writeLock!=null) {
+ writeLock.unlock();
+ }
+ }
+ skippedDoc = null;
+ saved(destination);
+ }
+
+ /**
+ * Update the modified time of the persisted domain.xml so that
+ * instances will detect it as changed.
+ * This is for triggering instance synchronization to occur.
+ */
+ public void touch() throws IOException {
+ getDestination().setLastModified(System.currentTimeMillis());
+ }
+
+ protected void saved(File destination) {
+ logger.fine("Configuration saved at " + destination);
+ }
+
+ protected File getDestination() throws IOException {
+ return new File(env.getConfigDirPath(), "domain.xml");
+ }
+
+ protected OutputStream getOutputStream(File destination) throws IOException {
+ return new FileOutputStream(destination);
+ }
+
+ /*
+ * The purpose of this service is to write out the domain.xml if any writes
+ * were skipped during startup of the server.
+ */
+ @Service
+ @RunLevel(PostStartupRunLevel.VAL)
+ static class SkippedWriteWriter implements PostConstruct {
+
+ @Inject DomainXmlPersistence domPersist;
+ @Inject Logger logger;
+
+ @Override
+ public void postConstruct() {
+ DomDocument doc = domPersist.skippedDoc;
+ if (doc != null) {
+ try {
+ domPersist.save(doc);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, localStrings.getLocalString("ioexception",
+ "IOException while saving the configuration, changes not persisted"), e);
+ }
+ }
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DynamicReloadService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DynamicReloadService.java
new file mode 100644
index 0000000..9a31831
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DynamicReloadService.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.config.serverbeans.Applications;
+import com.sun.enterprise.config.serverbeans.DasConfig;
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.internal.api.PostStartupRunLevel;
+import javax.inject.Inject;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.PreDestroy;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.config.ConfigListener;
+import org.jvnet.hk2.config.UnprocessedChangeEvent;
+import org.jvnet.hk2.config.UnprocessedChangeEvents;
+
+/**
+ * A service wrapper around the dynamic reload processor.
+ * <p>
+ * The module system will start this service during GlassFish start-up. In turn
+ * it will start the actual reload logic to run periodically.
+ * <p>
+ *
+ * @author tjquinn
+ */
+@Service
+@RunLevel(PostStartupRunLevel.VAL)
+public class DynamicReloadService implements ConfigListener, PostConstruct, PreDestroy {
+
+ @Inject
+ DasConfig activeDasConfig;
+
+ @Inject
+ Applications applications;
+
+ @Inject
+ ServiceLocator habitat;
+
+ private Logger logger;
+
+ private Timer timer;
+
+ private TimerTask timerTask;
+
+ private DynamicReloader reloader;
+
+ private static final String DEFAULT_POLL_INTERVAL_IN_SECONDS = "2";
+
+ private static final List<String> configPropertyNames = Arrays.asList(
+ "dynamic-reload-enabled", "dynamic-reload-poll-interval-in-seconds"
+ );
+
+ public DynamicReloadService() {
+ }
+
+ public void postConstruct() {
+ logger = KernelLoggerInfo.getLogger();
+ /*
+ * Create the dynamic reloader right away, even if its use is disabled
+ * currently. This way any initialization errors will appear early
+ * in the log rather than later if and when the reloader is
+ * enabled.
+ */
+ try {
+ logger.fine("[Reloader] ReloaderService starting");
+ reloader = new DynamicReloader(
+ applications,
+ habitat
+ );
+
+ if (isEnabled(activeDasConfig)) {
+ start(getPollIntervalInSeconds(activeDasConfig));
+ } else {
+ logger.fine("[Reloader] Reloader is configured as disabled, so NOT starting the periodic task");
+ }
+ logger.fine("[Reloader] Service start-up complete");
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionDRS, e);
+ }
+
+ }
+
+ public void preDestroy() {
+ stop();
+ }
+
+ static String getValue(String value, String defaultValue) {
+ return (value == null || value.equals("")) ? defaultValue : value;
+ }
+
+ private boolean isEnabled(DasConfig config) {
+ return Boolean.parseBoolean(config.getDynamicReloadEnabled());
+ }
+
+ private int getPollIntervalInSeconds(DasConfig config) {
+ int result;
+ try {
+ result = Integer.parseInt(config.getDynamicReloadPollIntervalInSeconds());
+ } catch (NumberFormatException e) {
+ result = Integer.parseInt(DEFAULT_POLL_INTERVAL_IN_SECONDS);
+ }
+ return result;
+ }
+
+ private void start(int pollIntervalInSeconds) {
+ long pollIntervalInMS = pollIntervalInSeconds * 1000L;
+ reloader.init();
+ timer = new Timer("DynamicReloader", true);
+ timer.schedule(
+ timerTask = new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ reloader.run();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ },
+ pollIntervalInMS,
+ pollIntervalInMS);
+ logger.fine("[Reloader] Started, monitoring every " +
+ pollIntervalInSeconds + " seconds"
+ );
+ }
+
+ private void stop() {
+ /*
+ * Tell the running autodeployer to stop, then cancel the timer task
+ * and the timer.
+ */
+ logger.fine("[Reloader] Stopping");
+ reloader.cancel();
+ if(timerTask != null) {
+ timerTask.cancel();
+ }
+ if (timer != null) {
+ timer.cancel();
+ }
+ }
+
+ /**
+ * Reschedules the autodeployer because a configuration change has altered
+ * the frequency.
+ */
+ private void reschedule(int pollIntervalInSeconds) {
+ logger.fine("[Reloader] Restarting...");
+ stop();
+ try {
+ reloader.waitUntilIdle();
+ } catch (InterruptedException e) {
+ // XXX OK to glide through here?
+ }
+ start(pollIntervalInSeconds);
+ }
+
+ public synchronized UnprocessedChangeEvents changed(PropertyChangeEvent[] events) {
+ /*
+ * Deal with any changes to the DasConfig that might affect whether
+ * the reloader should be stopped or started or rescheduled with a
+ * different frequency. Those change are handled here, by this
+ * class.
+ */
+
+ /* Record any events we tried to process but could not. */
+ List<UnprocessedChangeEvent> unprocessedEvents = new ArrayList<UnprocessedChangeEvent>();
+
+ Boolean newEnabled = null;
+ Integer newPollIntervalInSeconds = null;
+
+ for (PropertyChangeEvent event : events) {
+ String propName = event.getPropertyName();
+ if (event.getSource() instanceof DasConfig) {
+ if (configPropertyNames.contains(propName) && (event.getOldValue().equals(event.getNewValue()))) {
+ logger.fine("[DynamicReload] Ignoring reconfig of " + propName +
+ " from " + event.getOldValue() + " to " + event.getNewValue());
+ continue;
+ }
+ if (propName.equals("dynamic-reload-enabled")) {
+ /*
+ * Either start the currently stopped reloader or stop the
+ * currently running one.
+ */
+ newEnabled = Boolean.valueOf((String) event.getNewValue());
+ } else if (propName.equals("dynamic-reload-poll-interval-in-seconds")) {
+ try {
+ newPollIntervalInSeconds = new Integer((String) event.getNewValue());
+ } catch (NumberFormatException ex) {
+ String reason = ex.getClass().getName() + " " + ex.getLocalizedMessage();
+ logger.log(Level.WARNING, reason);
+ }
+ }
+ }
+ }
+ if (newEnabled != null) {
+ if (newEnabled) {
+ start(newPollIntervalInSeconds == null ? getPollIntervalInSeconds(activeDasConfig) : newPollIntervalInSeconds);
+ } else {
+ stop();
+ }
+ } else {
+ if (newPollIntervalInSeconds != null && isEnabled(activeDasConfig)) {
+ /*
+ * There is no change in whether the reloader should be running, only
+ * in how often it should run. If it is not running now don't
+ * start it. If it is running now, restart it to use the new
+ * polling interval.
+ */
+ reschedule(newPollIntervalInSeconds);
+ }
+ }
+ return (unprocessedEvents.size() > 0) ? new UnprocessedChangeEvents(unprocessedEvents) : null;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DynamicReloader.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DynamicReloader.java
new file mode 100644
index 0000000..94bb988
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/DynamicReloader.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.config.serverbeans.Application;
+import com.sun.enterprise.config.serverbeans.Applications;
+import com.sun.enterprise.config.serverbeans.ServerTags;
+import com.sun.enterprise.v3.admin.CommandRunnerImpl;
+import com.sun.enterprise.v3.common.XMLActionReporter;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Logger;
+import javax.security.auth.Subject;
+import org.glassfish.api.admin.ParameterMap;
+import org.glassfish.api.admin.config.ApplicationName;
+import org.glassfish.deployment.common.DeploymentProperties;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.api.InternalSystemAdministrator;
+import org.glassfish.kernel.KernelLoggerInfo;
+
+/**
+ * Triggers reloads of deployed applications depending on the presence of and
+ * timestamp on a .reload file in the application's top-level directory.
+ *
+ * An instance of this class can be reused, its run method invoked repeatedly
+ * to check all known apps for their .reload files.
+ *
+ * @author tjquinn
+ */
+public class DynamicReloader implements Runnable {
+
+ private static final String RELOAD_FILE_NAME = ".reload";
+
+ private static class SyncBoolean {
+ private boolean b = false;
+
+ private SyncBoolean(final boolean initialValue) {
+ b = initialValue;
+ }
+
+ private synchronized void set(final boolean value) {
+ b = value;
+ }
+
+ private synchronized boolean get() {
+ return b;
+ }
+ }
+ private final SyncBoolean inProgress;
+
+ /** Records info about apps being monitored */
+ private Map<String,AppReloadInfo> appReloadInfo;
+
+ private AtomicBoolean cancelRequested = new AtomicBoolean(false);
+
+ private Applications applications;
+
+ private Logger logger = KernelLoggerInfo.getLogger();
+
+ private ServiceLocator habitat;
+
+ private final Subject kernelSubject;
+
+ DynamicReloader(Applications applications, ServiceLocator habitat) throws URISyntaxException {
+ this.applications = applications;
+ this.habitat = habitat;
+ initAppReloadInfo(applications);
+ inProgress = new SyncBoolean(false);
+ final InternalSystemAdministrator kernelIdentity = habitat.getService(InternalSystemAdministrator.class);
+ kernelSubject = kernelIdentity.getSubject();
+ }
+
+ /**
+ * Records reload information about the currently-known applications.
+ *
+ * @param applications
+ */
+ private synchronized void initAppReloadInfo(Applications applications) throws URISyntaxException {
+ appReloadInfo = new HashMap<String,AppReloadInfo>();
+ logger.fine("[Reloader] Preparing list of apps to monitor:");
+ for (ApplicationName m : applications.getModules()) {
+ if (m instanceof Application) {
+ Application app = (Application) m;
+ if (Boolean.valueOf(app.getDeployProperties().getProperty
+ (ServerTags.IS_LIFECYCLE))) {
+ // skip lifecycle modules
+ continue;
+ }
+ AppReloadInfo info = new AppReloadInfo(app);
+ appReloadInfo.put(app.getName(), info);
+ logger.fine("[Reloader] Monitoring " + app.getName() + " at " + app.getLocation());
+ }
+ }
+ }
+
+ public void run() {
+ markInProgress();
+ try {
+ reloadApps();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ clearInProgress();
+ }
+ }
+
+ void cancel() {
+ cancelRequested.set(true);
+ }
+
+ void init() {
+ cancelRequested.set(false);
+ }
+
+ private void reloadApps() throws URISyntaxException, IOException {
+ List<AppReloadInfo> appsToReload = chooseAppsToReload();
+ for (AppReloadInfo appInfo : appsToReload) {
+ if (cancelRequested.get()) {
+ break;
+ }
+ reloadApp(appInfo);
+ }
+ }
+
+ private synchronized List<AppReloadInfo> chooseAppsToReload() throws URISyntaxException {
+ List<AppReloadInfo> result = new ArrayList<AppReloadInfo>();
+
+ /*
+ * The collectionof AppReloadInfo might not contain entries for all
+ * current apps (for example, if an app has been deployed since the
+ * previous run of the reloader). Use the current list of all known
+ * apps, and for each of those try to find an AppReloadInfo entry for
+ * it.
+ */
+ Set<AppReloadInfo> possiblyUndeployedApps = new HashSet<AppReloadInfo>(appReloadInfo.values());
+
+ for (ApplicationName m : applications.getModules()) {
+ if (m instanceof Application) {
+ Application app = (Application) m;
+ if (Boolean.valueOf(app.getDeployProperties().getProperty
+ (ServerTags.IS_LIFECYCLE))) {
+ // skip lifecycle modules
+ continue;
+ }
+ AppReloadInfo reloadInfo = findOrCreateAppReloadInfo(app);
+ if (reloadInfo.needsReload()) {
+ logger.fine("[Reloader] Selecting app " + reloadInfo.getApplication().getName() + " to reload");
+ result.add(reloadInfo);
+ }
+ possiblyUndeployedApps.remove(reloadInfo);
+ }
+ }
+
+ /*
+ * Remove any apps from the reload info that are no longer present.
+ */
+ for (AppReloadInfo info : possiblyUndeployedApps) {
+ logger.fine("[Reloader] Removing undeployed app " + info.getApplication().getName() + " from reload info");
+ appReloadInfo.remove(info.getApplication().getName());
+ }
+
+
+ return result;
+ }
+
+ private synchronized AppReloadInfo findOrCreateAppReloadInfo(Application app) throws URISyntaxException {
+ AppReloadInfo result = appReloadInfo.get(app.getName());
+ if (result == null) {
+ logger.fine("[Reloader] Recording info for new app " + app.getName() + " at " + app.getLocation());
+ result = new AppReloadInfo(app);
+ appReloadInfo.put(app.getName(), result);
+ }
+ return result;
+ }
+
+ private void reloadApp(AppReloadInfo appInfo) throws IOException {
+ logger.fine("[Reloader] Reloading " + appInfo.getApplication().getName());
+
+ /*
+ * Prepare a deploy command and invoke it, taking advantage of the
+ * DeployCommand's logic to deal with redeploying an existing app.
+ *
+ * Note that the redeployinplace internal option tells the undeploy
+ * command (which is invoked by the deploy command) to preserve the
+ * existing directory, even if the configuration does not indicate that
+ * the app is directory-deployed.
+ *
+ */
+ CommandRunnerImpl commandRunner = habitat.getService(CommandRunnerImpl.class);
+
+ ParameterMap deployParam = new ParameterMap();
+ deployParam.set(DeploymentProperties.FORCE, Boolean.TRUE.toString());
+ deployParam.set(DeploymentProperties.PATH, appInfo.getApplicationDirectory().getCanonicalPath());
+ deployParam.set(DeploymentProperties.NAME, appInfo.getApplication().getName());
+ deployParam.set(DeploymentProperties.KEEP_REPOSITORY_DIRECTORY, "true");
+ commandRunner.getCommandInvocation("deploy", new XMLActionReporter(), kernelSubject).parameters(deployParam).execute();
+
+
+ appInfo.recordLoad();
+ }
+
+ private void markInProgress() {
+ inProgress.set(true);
+ }
+
+ private void clearInProgress() {
+ synchronized(inProgress) {
+ inProgress.set(false);
+ inProgress.notifyAll();
+ }
+ }
+
+ public void waitUntilIdle() throws InterruptedException {
+ synchronized(inProgress) {
+ while (inProgress.get()) {
+ inProgress.wait();
+ }
+ }
+ }
+
+ /**
+ * Records information about every application, regardless of whether the
+ * app has a .reload file or not.
+ *
+ * The latestRecordedLoad time records either the object creation time (which should
+ * be about the same as the initial load time of the app during a server
+ * restart or after a deployment) or the time at which an app was reloaded.
+ *
+ * Note that this class uses the fact that lastModified of a non-existing
+ * file is 0.
+ */
+ private final static class AppReloadInfo {
+ /** points to the .reload file, whether one exists for this app or not */
+ private File reloadFile;
+
+ private long latestRecordedLoad;
+
+ /** application info */
+ private Application app;
+
+ private File appDir;
+
+ private AppReloadInfo(Application app) throws URISyntaxException {
+ this.app = app;
+ appDir = new File(new URI(app.getLocation()));
+ reloadFile = new File(appDir, RELOAD_FILE_NAME);
+ recordLoad();
+ }
+
+ private Application getApplication() {
+ return app;
+ }
+
+ private boolean needsReload() {
+ boolean answer = reloadFile.lastModified() > latestRecordedLoad;
+ return answer;
+ }
+
+ private void recordLoad() {
+ latestRecordedLoad = System.currentTimeMillis();
+ }
+
+ private File getApplicationDirectory() {
+ return appDir;
+ }
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ExecutorServiceFactory.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ExecutorServiceFactory.java
new file mode 100644
index 0000000..32b904f
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ExecutorServiceFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import org.glassfish.hk2.api.Factory;
+import org.jvnet.hk2.annotations.Service;
+import java.util.concurrent.ThreadFactory;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Singleton executor service factory.
+ *
+ * @author Jerome Dochez
+ */
+@Service
+public class ExecutorServiceFactory implements Factory<ExecutorService> {
+
+ /* (non-Javadoc)
+ * @see org.glassfish.hk2.api.Factory#provide()
+ */
+ @Override
+ public ExecutorService provide() {
+ return Executors.newCachedThreadPool(new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ Thread t = Executors.defaultThreadFactory().newThread(r);
+ t.setDaemon(true);
+ return t;
+ }
+ }
+ );
+ }
+
+ /* (non-Javadoc)
+ * @see org.glassfish.hk2.api.Factory#dispose(java.lang.Object)
+ */
+ @Override
+ public void dispose(ExecutorService instance) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/FighterFishStartupService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/FighterFishStartupService.java
new file mode 100644
index 0000000..ddb229e
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/FighterFishStartupService.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.glassfish.api.StartupRunLevel;
+import org.glassfish.hk2.api.ServiceHandle;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * This service is here to start fighterfish if it is available. This
+ * is done to maintain fighterfish compatibility with older versions
+ * of glassfish
+ *
+ * @author jwells
+ *
+ */
+@Service
+@RunLevel(value=StartupRunLevel.VAL, mode=RunLevel.RUNLEVEL_MODE_NON_VALIDATING)
+public class FighterFishStartupService {
+ private final static String FIGHTERFISH_START_SERVICE = "org.glassfish.osgijpa.extension.JPAStartupService";
+
+ @Inject
+ private ServiceLocator locator;
+
+ private List<ServiceHandle<?>> fighterFishHandles;
+
+ @SuppressWarnings("unused")
+ @PostConstruct
+ private void postConstruct() {
+ fighterFishHandles = locator.getAllServiceHandles(
+ BuilderHelper.createContractFilter(FIGHTERFISH_START_SERVICE));
+
+ for (ServiceHandle<?> fighterFishHandle : fighterFishHandles) {
+ fighterFishHandle.getService();
+ }
+
+ }
+
+ @SuppressWarnings("unused")
+ @PreDestroy
+ private void preDestroy() {
+ if (fighterFishHandles == null) return;
+
+ List<ServiceHandle<?>> localHandles = new LinkedList<ServiceHandle<?>>(fighterFishHandles);
+ fighterFishHandles.clear();
+
+ for (ServiceHandle<?> handle : localHandles) {
+ handle.destroy();
+ }
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/GFDomainXml.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/GFDomainXml.java
new file mode 100644
index 0000000..f147d88
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/GFDomainXml.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import org.glassfish.config.support.GlassFishDocument;
+import org.glassfish.config.support.DomainXml;
+import org.glassfish.internal.api.*;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.DomDocument;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * Subclass of domain.xml loader service to ensure that hk2 threads have access
+ * to the common class loader classes.
+ *
+ * @author Jerome Dochez
+ */
+@Service
+public class GFDomainXml extends DomainXml {
+
+ /**
+ * Returns the DomDocument implementation used to create config beans and persist
+ * the DOM tree.
+ *
+ * @return an instance of a DomDocument (or subclass)
+ */
+ protected DomDocument getDomDocument() {
+ return new GlassFishDocument(habitat,
+ Executors.newCachedThreadPool(new ThreadFactory() {
+
+ public Thread newThread(Runnable r) {
+ Thread t = Executors.defaultThreadFactory().newThread(r);
+ t.setDaemon(true);
+ t.setContextClassLoader(habitat.<ServerContext>getService(ServerContext.class).getCommonClassLoader());
+ return t;
+ }
+
+ }));
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LifecycleEventContextImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LifecycleEventContextImpl.java
new file mode 100755
index 0000000..da73f1a
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LifecycleEventContextImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.appserv.server.LifecycleEventContext;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.naming.InitialContext;
+import org.glassfish.internal.api.ServerContext;
+import org.glassfish.kernel.KernelLoggerInfo;
+
+public class LifecycleEventContextImpl implements LifecycleEventContext {
+
+ private ServerContext ctx;
+
+ private static final Logger logger = KernelLoggerInfo.getLogger();
+
+ /**
+ * public constructor
+ */
+ public LifecycleEventContextImpl(ServerContext ctx) {
+ this.ctx = ctx;
+ }
+
+ /**
+ * Get the server command-line arguments
+ */
+ public String[] getCmdLineArgs() {
+ return ctx.getCmdLineArgs();
+ }
+
+ /**
+ * Get server installation root
+ */
+ public String getInstallRoot() {
+ return ctx.getInstallRoot().getPath();
+ }
+
+ /**
+ * Get the server instance name
+ */
+ public String getInstanceName() {
+ return ctx.getInstanceName();
+ }
+
+ /**
+ * Get the initial naming context.
+ */
+ public InitialContext getInitialContext() {
+ return ctx.getInitialContext();
+ }
+
+ /**
+ * Writes the specified message to a server log file.
+ *
+ * @param msg a <code>String</code> specifying the
+ * message to be written to the log file
+ */
+ public void log(String message) {
+ logger.info(message);
+ }
+
+ /**
+ * Writes an explanatory message and a stack trace
+ * for a given <code>Throwable</code> exception
+ * to the server log file.
+ *
+ * @param message a <code>String</code> that
+ * describes the error or exception
+ *
+ * @param throwable the <code>Throwable</code> error
+ * or exception
+ */
+ public void log(String message, Throwable throwable) {
+ logger.log(Level.INFO, message, throwable);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LifecycleListenerImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LifecycleListenerImpl.java
new file mode 100755
index 0000000..01af866
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LifecycleListenerImpl.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import java.util.Properties;
+
+import com.sun.appserv.server.LifecycleListener;
+import com.sun.appserv.server.LifecycleEvent;
+import com.sun.appserv.server.LifecycleEventContext;
+import com.sun.appserv.server.ServerLifecycleException;
+
+/**
+ * LifecycleListenerImpl is a dummy implementation for the LifecycleListener interface.
+ * This implementaion stubs out various lifecycle interface methods.
+ */
+public class LifecycleListenerImpl implements LifecycleListener {
+
+ /** receive a server lifecycle event
+ * @param event associated event
+ * @throws <code>ServerLifecycleException</code> for exceptional condition.
+ *
+ * Configure this module as a lifecycle-module in server.xml:
+ *
+ * <applications>
+ * <lifecycle-module name="test"
+ * class-name="com.sun.appserv.server.LifecycleListenerImpl"
+ is-failure-fatal="false">
+ * <property name="foo" value="fooval"/>
+ * </lifecycle-module>
+ * </applications>
+ *
+ * Set<code>is-failure-fatal</code>in server.xml to <code>true</code> for
+ * fatal conditions.
+ */
+ public void handleEvent(LifecycleEvent event) throws ServerLifecycleException {
+ LifecycleEventContext ctx = event.getLifecycleEventContext();
+
+ ctx.log("got event" + event.getEventType() + " event data: " + event.getData());
+
+ Properties props;
+
+ if (LifecycleEvent.INIT_EVENT == event.getEventType()) {
+ System.out.println("LifecycleListener: INIT_EVENT");
+
+ props = (Properties) event.getData();
+
+ // handle INIT_EVENT
+ return;
+ }
+
+ if (LifecycleEvent.STARTUP_EVENT == event.getEventType()) {
+ System.out.println("LifecycleListener: STARTUP_EVENT");
+
+ // handle STARTUP_EVENT
+ return;
+ }
+
+ if (LifecycleEvent.SHUTDOWN_EVENT== event.getEventType()) {
+ System.out.println("LifecycleListener: SHUTDOWN_EVENT");
+
+ // handle SHUTDOWN_EVENT
+ return;
+ }
+
+ if (LifecycleEvent.TERMINATION_EVENT == event.getEventType()) {
+ System.out.println("LifecycleListener: TERMINATE_EVENT");
+
+ // handle TERMINATION_EVENT
+ return;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LifecycleModuleService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LifecycleModuleService.java
new file mode 100755
index 0000000..35f878c
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LifecycleModuleService.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.glassfish.api.FutureProvider;
+import org.glassfish.api.StartupRunLevel;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.deployment.common.DeploymentException;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.PreDestroy;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.internal.api.ServerContext;
+import org.jvnet.hk2.annotations.Service;
+
+import com.sun.appserv.server.LifecycleListener;
+import com.sun.appserv.server.ServerLifecycleException;
+import com.sun.enterprise.config.serverbeans.Application;
+import com.sun.enterprise.config.serverbeans.Applications;
+import com.sun.enterprise.config.serverbeans.ConfigBeansUtilities;
+import com.sun.enterprise.config.serverbeans.Server;
+import com.sun.enterprise.config.serverbeans.ServerTags;
+import com.sun.enterprise.util.Result;
+
+/**
+ * Support class to assist in firing LifecycleEvent notifications to
+ * registered LifecycleListeners.
+ */
+@Service
+@RunLevel(StartupRunLevel.VAL)
+public class LifecycleModuleService implements PreDestroy, PostConstruct, EventListener, FutureProvider<Result<Thread>>{
+
+ @Inject
+ ServerContext context;
+
+ @Inject
+ Applications apps;
+
+ @Inject
+ Events events;
+
+ @Inject @Named( ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Server server;
+
+ @Inject
+ private ConfigBeansUtilities configBeansUtilities;
+
+ /**
+ * The set of registered LifecycleListeners for event notifications.
+ */
+ private ArrayList listeners = new ArrayList();
+
+ List<Future<Result<Thread>>> futures = new ArrayList();
+
+ public void postConstruct() {
+ events.register(this);
+ try {
+ onInitialization();
+ } catch (Exception e) {
+ addExceptionToFuture(e);
+ }
+ }
+
+ public void preDestroy() {
+ try {
+ onTermination();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public List<Future<Result<Thread>>> getFutures() {
+ return futures;
+ }
+
+ public void event(Event event) {
+ try {
+ if (event.is(EventTypes.SERVER_STARTUP)) {
+ onStartup();
+ } else if (event.is(EventTypes.SERVER_READY)) {
+ onReady();
+ } else if (event.is(EventTypes.PREPARE_SHUTDOWN)) {
+ onShutdown();
+ }
+ } catch (Exception e) {
+ throw new DeploymentException(e);
+ }
+ }
+
+ private void onInitialization() throws ServerLifecycleException {
+ List<Application> applications = apps.getApplications();
+ List<Application> lcms = new ArrayList<Application>();;
+ for (Application app : applications) {
+ if (Boolean.valueOf(app.getDeployProperties().getProperty
+ (ServerTags.IS_LIFECYCLE))) {
+ lcms.add(app);
+ }
+ }
+
+ HashSet listenerSet = new HashSet();
+ for (Application next : lcms) {
+ Properties props = next.getDeployProperties();
+ String enabled = next.getEnabled();
+ if ( isEnabled(next.getName(), enabled) ) {
+ String strOrder = (String)props.remove(
+ ServerTags.LOAD_ORDER);
+
+ int order = Integer.MAX_VALUE;
+ if (strOrder != null && strOrder.length() > 0) {
+ try {
+ order = Integer.parseInt(strOrder);
+ } catch(NumberFormatException nfe) {
+ nfe.printStackTrace();
+ }
+ }
+
+ String className = (String)props.remove(
+ ServerTags.CLASS_NAME);
+ ServerLifecycleModule slcm =
+ new ServerLifecycleModule(context,
+ next.getName(), className);
+
+ slcm.setLoadOrder(order);
+
+ String classpath = (String)props.remove(
+ ServerTags.CLASSPATH);
+ slcm.setClasspath(classpath);
+
+ String isFailureFatal = (String)props.remove(
+ ServerTags.IS_FAILURE_FATAL);
+ slcm.setIsFatal(Boolean.valueOf(isFailureFatal));
+
+ props.remove(ServerTags.IS_LIFECYCLE);
+ props.remove(ServerTags.OBJECT_TYPE);
+
+ for (String propName : props.stringPropertyNames()) {
+ slcm.setProperty(propName, props.getProperty(propName));
+ }
+
+ LifecycleListener listener = slcm.loadServerLifecycle();
+ listenerSet.add(slcm);
+ }
+ }
+ sortModules(listenerSet);
+
+ initialize();
+ }
+
+ /**
+ * Returns true if life cycle module is enabled in the application
+ * level and in the application ref level.
+ *
+ * @return true if life cycle module is enabled
+ */
+ private boolean isEnabled(String name, String enabled) {
+
+ // true if enabled in both lifecyle module and in the ref
+ return (Boolean.valueOf(enabled) &&
+ Boolean.valueOf(configBeansUtilities.getEnabled(
+ server.getName(), name)));
+ }
+
+ private void resetClassLoader(final ClassLoader c) {
+ // set the common class loader as the thread context class loader
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Object run() {
+ Thread.currentThread().setContextClassLoader(c);
+ return null;
+ }
+ }
+ );
+ }
+
+ private void sortModules(HashSet listenerSet) {
+ // FIXME: use a better sorting algo
+ for(Iterator iter = listenerSet.iterator(); iter.hasNext();) {
+ ServerLifecycleModule next = (ServerLifecycleModule) iter.next();
+ int order = next.getLoadOrder();
+ int i=0;
+ for(;i<this.listeners.size();i++) {
+ if(((ServerLifecycleModule)listeners.get(i)).getLoadOrder() > order) {
+ break;
+ }
+ }
+ this.listeners.add(i,next);
+ }
+ }
+
+ private void initialize()
+ throws ServerLifecycleException {
+
+ if (listeners.isEmpty())
+ return;
+
+ final ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ for(Iterator iter = listeners.iterator(); iter.hasNext();) {
+ ServerLifecycleModule next = (ServerLifecycleModule) iter.next();
+ next.onInitialization();
+ }
+ // set it back
+ resetClassLoader(cl);
+ }
+
+ private void onStartup() throws ServerLifecycleException {
+
+ if (listeners.isEmpty())
+ return;
+
+ final ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ for(Iterator iter = listeners.iterator(); iter.hasNext();) {
+ ServerLifecycleModule next = (ServerLifecycleModule) iter.next();
+ next.onStartup();
+ }
+ // set it back
+ resetClassLoader(cl);
+ }
+
+ private void onReady() throws ServerLifecycleException {
+
+ if (listeners.isEmpty())
+ return;
+
+ final ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ for(Iterator iter = listeners.iterator(); iter.hasNext();) {
+ ServerLifecycleModule next = (ServerLifecycleModule) iter.next();
+ next.onReady();
+ }
+ // set it back
+ resetClassLoader(cl);
+ }
+
+ private void onShutdown() throws ServerLifecycleException {
+
+ if (listeners.isEmpty())
+ return;
+
+ final ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ for(Iterator iter = listeners.iterator(); iter.hasNext();) {
+ ServerLifecycleModule next = (ServerLifecycleModule) iter.next();
+ next.onShutdown();
+ }
+ // set it back
+ resetClassLoader(cl);
+ }
+
+ private void onTermination() throws ServerLifecycleException {
+
+ if (listeners.isEmpty())
+ return;
+
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ for(Iterator iter = listeners.iterator(); iter.hasNext();) {
+ ServerLifecycleModule next = (ServerLifecycleModule) iter.next();
+ next.onTermination();
+ }
+ // set it back
+ resetClassLoader(cl);
+ }
+
+ private Future<Result<Thread>> addExceptionToFuture(Throwable t) {
+ Future<Result<Thread>> future = new LifecycleModuleFuture();
+ ((LifecycleModuleFuture)future).setResult(new Result<Thread>(t));
+ futures.add(future);
+ return future;
+ }
+
+ public static final class LifecycleModuleFuture implements Future<Result<Thread>> {
+ Result<Thread> result;
+ CountDownLatch latch = new CountDownLatch(1);
+
+ public void setResult(Result<Thread> result) {
+ this.result = result;
+ latch.countDown();
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return latch.getCount() == 0;
+ }
+
+ @Override
+ public Result<Thread> get() throws InterruptedException {
+ latch.await();
+ return result;
+ }
+
+ @Override
+ public Result<Thread> get(long timeout, TimeUnit unit) throws InterruptedException {
+ latch.await(timeout, unit);
+ return result;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LocalStrings.properties b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LocalStrings.properties
new file mode 100644
index 0000000..6e8eb8a
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/LocalStrings.properties
@@ -0,0 +1,57 @@
+#
+# Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+
+
+appnamenotunique=Application name {0} is already in use. Please pick a different name.
+unknownmoduletpe=Module type not recognized for module {0}
+unknownarchivetype=Archive type of {0} was not recognized
+unknowncontainertype=There is no installed container capable of handling this application {0}
+deploy.unknowncontainer={0} is not a recognized container
+deploy.isolationerror=Container {0} does not support other components containers to be turned off, --type {0} is forbidden
+invalidarchivepackaging=Sniffers with type [{0}] and type [{1}] should not claim the archive at the same time. Please check the packaging of your archive [{2}]
+internal_error=Internal Error: {0}
+bad_config_dir=The domain''s config directory does not exist: {0}
+cant_delete_pid_file=Unable to delete the process id file ({0}). Please delete it.
+application.alreadyreg.redeploy=Application with name {0} is already registered. Either specify that redeployment must be forced, or redeploy the application. Or if this is a new deployment, pick a different name
+use.create_app_ref=Application {0} is already deployed on other targets. Please use create-application-ref command to create application reference on target {1}
+use.create_app_ref_2=Application {0} is already deployed in this domain. Please use create-application-ref command to create application reference on target {1}
+redeploy_on_multiple_targets=Application {0} is referenced by more than one targets. Please remove other references or specify all targets (or domain target if using asadmin command line) before attempting redeploy operation
+undeploy_on_multiple_targets=Application {0} is referenced by more than one targets. Please remove other references or specify all targets (or domain target if using asadmin command line) before attempting undeploy operation.
+delete_lifecycle_on_multiple_targets=Lifecycle module {0} is referenced by more than one targets. Please remove other references before attempting delete operation.
+cannot_specify_managed_target=Cannot specify target {0} for the operation. Target {0} is a managed target
+
+application.deploy_domain=Application with name {0} is already referenced by other target(s). Please specify force option to redeploy to domain.
+error.deploying.app=Exception while deploying the app [{0}]
+
+cannotCreateLockFile=Cannot create lock file at {0}, configuration changes will not be persisted
+InvalidLocation=Cannot obtain lockfile location {0}, configuration changes will not be persisted
+NoLocation=domain.xml cannot be persisted, null destination
+Timeout=Timed out when waiting for write lock on configuration file
+NoTmpFile=Cannot create temporary file when saving domain.xml
+TmpFileNotSaved=Configuration could not be saved to temporary file
+CloseFailed=Cannot close configuration writer stream
+ioexception=IOException while saving the configuration, changes not persisted
+RenameFailed=Could not rename backup to {0}
+TmpRenameFailed=Could not rename {0} to {1}
+BackupDeleteFailed=Could not delete previous backup file at {0}
+
+lifecyclemodule.loadExceptionIsFatal=Treating failure loading the lifecycle module [{0}] as fatal; please check your classpath and the is-failure-fatal property.
+lifecyclemodule.preInvoke_exception=Exception lifecycle module [{0}] during pre-invocation.
+lifecyclemodule.postInvoke_exception=Exception lifecycle module [{0}] during post-invocation.
+lifecyclemodule.event_exceptionIsFatal=Treating the exception from lifecycle module event handler as fatal; please check the is-failure-fatal property.
+
+
+fnf=File not found {0}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ReadableArchiveScannerAdapter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ReadableArchiveScannerAdapter.java
new file mode 100644
index 0000000..0b5ad3a
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ReadableArchiveScannerAdapter.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Enumeration;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.jar.Manifest;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.api.deployment.archive.ReadableArchive;
+import org.glassfish.hk2.classmodel.reflect.ArchiveAdapter;
+import org.glassfish.hk2.classmodel.reflect.Parser;
+import org.glassfish.hk2.classmodel.reflect.util.AbstractAdapter;
+import org.glassfish.kernel.KernelLoggerInfo;
+
+/**
+ * ArchiveAdapter for DOL readable archive instances
+ *
+ * @author Jerome Dochez
+ */
+public class ReadableArchiveScannerAdapter extends AbstractAdapter {
+
+ final ReadableArchive archive;
+ final Parser parser;
+ final URI uri;
+
+ /**
+ * Can be null or can be pointing to the archive adapter in which
+ * we are embedded.
+ */
+ final ReadableArchiveScannerAdapter parent;
+
+ /**
+ * We need to maintain a count of the sub archives we have asked
+ * the class-model to parse so we can close our archive once all
+ * the sub-archives have been closed themselves.
+ *
+ * Obviously, we start with a count of 1 since we need to account
+ * for our own closure.
+ *
+ */
+ final AtomicInteger releaseCount = new AtomicInteger(1);
+
+ /**
+ * Default timeout value for parsing a single jar (plus all internal jars it may contains)
+ */
+ private final int DEFAULT_TIMEOUT = Integer.getInteger(Parser.DEFAULT_WAIT_SYSPROP, 600);
+
+ private final static Level level = Level.FINE;
+ final private static Logger alogger = KernelLoggerInfo.getLogger();
+
+
+ public ReadableArchiveScannerAdapter(Parser parser, ReadableArchive archive) {
+ this.archive = archive;
+ this.parser = parser;
+ this.uri = archive.getURI();
+ this.parent = null;
+ }
+
+ private ReadableArchiveScannerAdapter(ReadableArchiveScannerAdapter parent, ReadableArchive archive, URI uri) {
+ this.parent = parent;
+ this.archive = archive;
+ this.parser = parent.parser;
+ this.uri = uri==null?archive.getURI():uri;
+ }
+
+ @Override
+ public URI getURI() {
+ return uri;
+ }
+
+ @Override
+ public Manifest getManifest() throws IOException {
+ return archive.getManifest();
+ }
+
+ @Override
+ public void onSelectedEntries(ArchiveAdapter.Selector selector, EntryTask entryTask, final Logger logger ) throws IOException {
+
+ Enumeration<String> entries = archive.entries();
+ while (entries.hasMoreElements()) {
+ final String name = entries.nextElement();
+ Entry entry = new Entry(name, archive.getEntrySize(name), false);
+ if (selector.isSelected(entry)) {
+ handleEntry(name, entry, logger, entryTask);
+ }
+ // check for non exploded jars.
+ if (name.endsWith(".jar")) {
+ handleJar(name, logger);
+ }
+ }
+ if (logger.isLoggable(level)) {
+ logger.log(level, "Finished parsing " + this.uri);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ releaseCount();
+ }
+
+ private void releaseCount() throws IOException {
+ int release = releaseCount.decrementAndGet();
+ if (release==0) {
+ archive.close();
+ if (parent!=null) {
+ parent.releaseCount();
+ }
+ }
+ }
+
+ protected void handleEntry(String name, Entry entry, Logger logger /*ignored*/, EntryTask entryTask)
+ throws IOException {
+
+ InputStream is = null;
+ try {
+ try {
+ is = archive.getEntry(name);
+ if (is==null) {
+ alogger.log(Level.SEVERE, KernelLoggerInfo.invalidInputStream, name);
+ return;
+ }
+ entryTask.on(entry, is);
+ } catch (Exception e) {
+ alogger.log(Level.SEVERE, KernelLoggerInfo.exceptionWhileParsing,
+ new Object[] { entry.name, archive.getURI(), entry.size, e});
+ }
+ } finally {
+ if (is!=null)
+ is.close();
+ }
+ }
+
+ protected Future handleJar(final String name, final Logger logger)
+ throws IOException {
+
+ // we need to check that there is no exploded directory by this name.
+ String explodedName = name.replaceAll("[/ ]", "__").replace(".jar", "_jar");
+ if (!archive.exists(explodedName)) {
+
+ final ReadableArchive subArchive = archive.getSubArchive(name);
+ if (subArchive==null) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.cantOpenSubArchive,
+ new Object[] {name, archive.getURI()});
+ return null;
+ }
+
+ if (logger.isLoggable(level)) {
+ logger.log(level, "Spawning sub parsing " + subArchive.getURI());
+ }
+ final ReadableArchiveScannerAdapter adapter = new InternalJarAdapter(this, subArchive, subArchive.getURI());
+ // we increment our release count, this tells us when we can safely close the parent
+ // archive.
+ releaseCount.incrementAndGet();
+ return parser.parse(adapter, new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (logger.isLoggable(level))
+ logger.log(level, "Closing sub archive " + subArchive.getURI());
+ adapter.close();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionWhileClosing,
+ new Object[] { name, e });
+ }
+ }
+ });
+ }
+ return null;
+ }
+
+ /**
+ * Adapter for internal jar files. we don't process further down any more internal
+ * jar files. In other words, no jars inside jars inside jars can be deployed...
+ */
+ private static class InternalJarAdapter extends ReadableArchiveScannerAdapter {
+ public InternalJarAdapter(ReadableArchiveScannerAdapter parent, ReadableArchive archive, URI uri) {
+ super(parent, archive, uri);
+ }
+
+ @Override
+ protected Future handleJar(String name, Logger logger) throws IOException {
+ // we don't process second level internal jars
+ return null;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ScheduledExecutorServiceFactory.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ScheduledExecutorServiceFactory.java
new file mode 100644
index 0000000..f36f1d5
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ScheduledExecutorServiceFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import org.glassfish.hk2.api.Factory;
+import org.jvnet.hk2.annotations.Service;
+import java.util.concurrent.ThreadFactory;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Factory to create the scheduled executor service
+ *
+ * @author Jerome Dochez
+ */
+@Service
+public class ScheduledExecutorServiceFactory implements Factory<ScheduledExecutorService> {
+
+ /* (non-Javadoc)
+ * @see org.glassfish.hk2.api.Factory#provide()
+ */
+ @Override
+ public ScheduledExecutorService provide() {
+ return Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ Thread t = Executors.defaultThreadFactory().newThread(r);
+ t.setDaemon(true);
+ return t;
+ }
+ }
+ );
+ }
+
+ /* (non-Javadoc)
+ * @see org.glassfish.hk2.api.Factory#dispose(java.lang.Object)
+ */
+ @Override
+ public void dispose(ScheduledExecutorService instance) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ServerContextImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ServerContextImpl.java
new file mode 100644
index 0000000..a2e9363
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ServerContextImpl.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import org.glassfish.server.ServerEnvironmentImpl;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.glassfish.bootstrap.StartupContextUtil;
+import org.glassfish.internal.api.ClassLoaderHierarchy;
+import org.glassfish.internal.api.ServerContext;
+import org.glassfish.api.invocation.InvocationManager;
+import org.glassfish.api.naming.GlassfishNamingManager;
+import javax.inject.Inject;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.ServiceLocator;
+
+import javax.inject.Singleton;
+
+import javax.naming.InitialContext;
+import java.io.File;
+import java.util.Map;
+
+/**
+ * This is the Server Context object.
+ *
+ * @author Jerome Dochez
+ */
+@Service
+@Singleton
+public class ServerContextImpl implements ServerContext, PostConstruct {
+
+ @Inject
+ ServerEnvironmentImpl env;
+
+ @Inject
+ StartupContext startupContext;
+
+ @Inject
+ ServiceLocator services;
+
+ File instanceRoot;
+ String[] args;
+
+ /** Creates a new instance of ServerContextImpl */
+ public void postConstruct() {
+ this.instanceRoot = env.getDomainRoot();
+ this.args = new String[startupContext.getArguments().size()*2];
+ int i=0;
+ for (Map.Entry<Object, Object> entry : startupContext.getArguments().entrySet()) {
+ args[i++] = entry.getKey().toString();
+ args[i++] = entry.getValue().toString();
+ }
+ }
+
+ public File getInstanceRoot() {
+ return instanceRoot;
+ }
+
+ public String[] getCmdLineArgs() {
+ return args;
+ }
+
+ public File getInstallRoot() {
+ return StartupContextUtil.getInstallRoot(startupContext);
+ }
+
+ public String getInstanceName() {
+ return env.getInstanceName();
+ }
+
+ public String getServerConfigURL() {
+ File domainXML = new File(instanceRoot, ServerEnvironmentImpl.kConfigDirName);
+ domainXML = new File(domainXML, ServerEnvironmentImpl.kConfigXMLFileName);
+ return domainXML.toURI().toString();
+ }
+
+ public com.sun.enterprise.config.serverbeans.Server getConfigBean() {
+ return services.getService(com.sun.enterprise.config.serverbeans.Server.class);
+ }
+
+ public InitialContext getInitialContext() {
+ GlassfishNamingManager gfNamingManager =
+ services.getService(GlassfishNamingManager.class);
+ return (InitialContext)gfNamingManager.getInitialContext();
+ }
+
+ public ClassLoader getCommonClassLoader() {
+ return services.<CommonClassLoaderServiceImpl>getService(CommonClassLoaderServiceImpl.class).getCommonClassLoader();
+ }
+
+ public ClassLoader getSharedClassLoader() {
+ return services.<ClassLoaderHierarchy>getService(ClassLoaderHierarchy.class).getConnectorClassLoader(null);
+ }
+
+ public ClassLoader getLifecycleParentClassLoader() {
+ return services.<ClassLoaderHierarchy>getService(ClassLoaderHierarchy.class).getConnectorClassLoader(null);
+ }
+
+ public InvocationManager getInvocationManager() {
+ return services.getService(InvocationManager.class);
+ }
+
+ public String getDefaultDomainName() {
+ return "glassfish-web";
+ }
+ /**
+ * Returns the default services for this instance
+ * @return default services
+ */
+ public ServiceLocator getDefaultServices() {
+ return services;
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ServerLifecycleModule.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ServerLifecycleModule.java
new file mode 100755
index 0000000..3ac2123
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ServerLifecycleModule.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.appserv.server.LifecycleEvent;
+import com.sun.appserv.server.LifecycleEventContext;
+import com.sun.appserv.server.LifecycleListener;
+import com.sun.appserv.server.ServerLifecycleException;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.List;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.internal.api.ServerContext;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.glassfish.loader.util.ASClassLoaderUtil;
+
+/**
+ * @author Sridatta Viswanath
+ */
+
+public final class ServerLifecycleModule {
+
+ private LifecycleListener slcl;
+ private String name;
+ private String className;
+ private String classpath;
+ private int loadOrder;
+ private boolean isFatal = false;
+ private String statusMsg = "OK";
+
+ private ServerContext ctx;
+ private LifecycleEventContext leContext;
+ private ClassLoader urlClassLoader;
+ private Properties props = new Properties();
+
+ private static final Logger _logger = KernelLoggerInfo.getLogger();
+ private static boolean _isTraceEnabled = false;
+
+ private final static String LIFECYCLE_PREFIX = "lifecycle_";
+
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ServerLifecycleModule.class);
+
+ ServerLifecycleModule(ServerContext ctx, String name, String className) {
+ this.name = name;
+ this.className = className;
+ this.ctx = ctx;
+ this.leContext = new LifecycleEventContextImpl(ctx);
+
+ _isTraceEnabled = _logger.isLoggable(Level.FINE);
+ }
+
+ void setClasspath(String classpath) {
+ this.classpath = classpath;
+ }
+
+ void setProperty(String name, String value) {
+ props.put(name, value);
+ }
+
+ Properties getProperties() {
+ return this.props;
+ }
+
+ void setLoadOrder(int loadOrder) {
+ this.loadOrder = loadOrder;
+ }
+
+ void setIsFatal(boolean isFatal) {
+ this.isFatal = isFatal;
+ }
+
+ String getName() {
+ return this.name;
+ }
+
+ String getClassName() {
+ return this.className;
+ }
+
+ String getClasspath() {
+ return this.classpath;
+ }
+
+ int getLoadOrder() {
+ return this.loadOrder;
+ }
+
+ boolean isFatal() {
+ return isFatal;
+ }
+
+ LifecycleListener loadServerLifecycle() throws ServerLifecycleException {
+ ClassLoader classLoader = ctx.getLifecycleParentClassLoader();
+
+ try {
+ if (this.classpath != null) {
+ URL[] urls = getURLs();
+
+ if (urls != null) {
+ StringBuffer sb = new StringBuffer(128);
+ for(int i=0;i<urls.length;i++) {
+ sb.append(urls[i].toString());
+ }
+ if (_isTraceEnabled)
+ _logger.fine("Lifecycle module = " + getName() +
+ " has classpath URLs = " + sb.toString());
+ }
+
+ this.urlClassLoader = new URLClassLoader(urls, classLoader);
+ classLoader = this.urlClassLoader;
+ }
+
+ Class cl = Class.forName(className, true, classLoader);
+ slcl = (LifecycleListener) cl.newInstance();
+ } catch (Exception ee) {
+ _logger.log(Level.SEVERE, KernelLoggerInfo.exceptionLoadingLifecycleModule,
+ new Object[] {this.name, ee}) ;
+ if (isFatal) {
+ throw new ServerLifecycleException(localStrings.getLocalString("lifecyclemodule.loadExceptionIsFatal", "Treating failure loading the lifecycle module as fatal", this.name));
+ }
+ }
+
+ return slcl;
+ }
+
+ private URL[] getURLs() {
+ List<URL> urlList = ASClassLoaderUtil.getURLsFromClasspath(
+ this.classpath, File.pathSeparator, "");
+ return ASClassLoaderUtil.convertURLListToArray(urlList);
+ }
+
+ private void postEvent(int eventType, Object data)
+ throws ServerLifecycleException {
+ if (slcl == null) {
+ if (isFatal) {
+ throw new ServerLifecycleException(localStrings.getLocalString("lifecyclemodule.loadExceptionIsFatal", "Treating failure loading the lifecycle module as fatal", this.name));
+ }
+
+ return;
+ }
+
+ if (urlClassLoader != null)
+ setClassLoader();
+
+ LifecycleEvent slcEvent= new LifecycleEvent(this, eventType, data, this.leContext);
+ try {
+ slcl.handleEvent(slcEvent);
+ } catch (ServerLifecycleException sle) {
+ _logger.log(Level.WARNING, KernelLoggerInfo.serverLifecycleException,
+ new Object[] {this.name, sle});
+
+ if (isFatal)
+ throw sle;
+ } catch (Exception ee) {
+ _logger.log(Level.WARNING, KernelLoggerInfo.lifecycleModuleException,
+ new Object[] {this.name, ee});
+
+ if (isFatal) {
+ throw new ServerLifecycleException(localStrings.getLocalString("lifecyclemodule.event_exceptionIsFatal", "Treating the exception from lifecycle module event handler as fatal"), ee);
+ }
+ }
+ }
+
+ public void onInitialization()
+ throws ServerLifecycleException {
+ postEvent(LifecycleEvent.INIT_EVENT, props);
+ }
+
+ public void onStartup()
+ throws ServerLifecycleException {
+ postEvent(LifecycleEvent.STARTUP_EVENT, props);
+ }
+
+ public void onReady() throws ServerLifecycleException {
+ postEvent(LifecycleEvent.READY_EVENT, props);
+ }
+
+ public void onShutdown() throws ServerLifecycleException {
+ postEvent(LifecycleEvent.SHUTDOWN_EVENT, props);
+ }
+
+ public void onTermination() throws ServerLifecycleException {
+ postEvent(LifecycleEvent.TERMINATION_EVENT, props);
+ }
+
+ private void setClassLoader() {
+ // set the url class loader as the thread context class loader
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Object run() {
+ Thread.currentThread().setContextClassLoader(urlClassLoader);
+ return null;
+ }
+ }
+ );
+ }
+
+ /**
+ * return status of this lifecycle module as a string
+ */
+ public String getStatus() {
+ return statusMsg;
+ }
+
+ public String toString() {
+ return "Server LifecycleListener support";
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SnifferManagerImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SnifferManagerImpl.java
new file mode 100644
index 0000000..e11eb24
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SnifferManagerImpl.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.classmodel.reflect.*;
+import javax.inject.Inject;
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.api.deployment.DeploymentContext;
+import org.glassfish.api.container.Sniffer;
+import org.glassfish.api.deployment.archive.ReadableArchive;
+import org.glassfish.api.deployment.archive.ArchiveHandler;
+import org.glassfish.api.deployment.archive.ArchiveType;
+import org.glassfish.internal.deployment.SnifferManager;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+
+import java.lang.annotation.Annotation;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Provide convenience methods to deal with {@link Sniffer}s in the system.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+@Service
+public class SnifferManagerImpl implements SnifferManager {
+ final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(SnifferManagerImpl.class);
+
+ @Inject
+ protected ServiceLocator habitat;
+
+ /**
+ * Returns all the presently registered sniffers
+ *
+ * @return Collection (possibly empty but never null) of Sniffer
+ */
+ public Collection<Sniffer> getSniffers() {
+ // this is a little bit of a hack, sniffers are now ordered by their names
+ // which is useful since connector is before ejb which is before web so if
+ // a standalone module happens to implement the three types of components,
+ // they will be naturally ordered correctly. We might want to revisit this
+ // later and formalize the ordering of sniffers. The hard thing as usual
+ // is that sniffers are highly pluggable so you never know which sniffers
+ // set you are working with depending on the distribution
+ List<Sniffer> sniffers = new ArrayList<Sniffer>();
+ sniffers.addAll(habitat.<Sniffer>getAllServices(Sniffer.class));
+ Collections.sort(sniffers, new Comparator<Sniffer>() {
+ public int compare(Sniffer o1, Sniffer o2) {
+ return o1.getModuleType().compareTo(o2.getModuleType());
+ }
+ });
+
+ return sniffers;
+ }
+
+ /**
+ * Check if there's any {@link Sniffer} installed at all.
+ */
+ public final boolean hasNoSniffers() {
+ return getSniffers().isEmpty();
+ }
+
+ public Sniffer getSniffer(String appType) {
+ assert appType!=null;
+ for (Sniffer sniffer : getSniffers()) {
+ if (appType.equalsIgnoreCase(sniffer.getModuleType())) {
+ return sniffer;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a collection of sniffers that recognized some parts of the
+ * passed archive as components their container handle.
+ *
+ * If no sniffer recognize the passed archive, an empty collection is
+ * returned.
+ *
+ * @param context the deployment context
+ * @return possibly empty collection of sniffers that handle the passed
+ * archive.
+ */
+ public Collection<Sniffer> getSniffers(DeploymentContext context) {
+ ReadableArchive archive = context.getSource();
+ ArchiveHandler handler = context.getArchiveHandler();
+ List<URI> uris = handler.getClassPathURIs(archive);
+ Types types = context.getTransientAppMetaData(Types.class.getName(), Types.class);
+ return getSniffers(context, uris, types);
+ }
+
+ public Collection<Sniffer> getSniffers(DeploymentContext context, List<URI> uris, Types types) {
+ // it is important to keep an ordered sequence here to keep sniffers
+ Collection<Sniffer> regularSniffers = getSniffers();
+
+ // in their natural order.
+ // scan for registered annotations and retrieve applicable sniffers
+ List<Sniffer> appSniffers = this.getApplicableSniffers(context, uris, types, regularSniffers, true);
+
+ // call handles method of the sniffers
+ for (Sniffer sniffer : regularSniffers) {
+ if ( !appSniffers.contains(sniffer) && sniffer.handles(context)) {
+ appSniffers.add(sniffer);
+ }
+ }
+ return appSniffers;
+ }
+
+ private <T extends Sniffer> List<T> getApplicableSniffers(DeploymentContext context, List<URI> uris, Types types, Collection<T> sniffers, boolean checkPath) {
+ ArchiveType archiveType = habitat.getService(ArchiveType.class, context.getArchiveHandler().getArchiveType());
+
+ if (sniffers==null || sniffers.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ List<T> result = new ArrayList<T>();
+ for (T sniffer : sniffers) {
+ if (archiveType != null &&
+ !sniffer.supportsArchiveType(archiveType)) {
+ continue;
+ }
+ String[] annotationNames = sniffer.getAnnotationNames(context);
+ if (annotationNames==null) continue;
+ for (String annotationName : annotationNames) {
+ if (types != null) {
+ Type type = types.getBy(annotationName);
+ if (type instanceof AnnotationType) {
+ Collection<AnnotatedElement> elements = ((AnnotationType) type).allAnnotatedTypes();
+ for (AnnotatedElement element : elements) {
+ if (checkPath) {
+ Type t = (element instanceof Member?((Member) element).getDeclaringType():(Type) element);
+ if (t.wasDefinedIn(uris)) {
+ result.add(sniffer);
+ break;
+ }
+ } else {
+ result.add(sniffer);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public void validateSniffers(Collection<? extends Sniffer> snifferCol, DeploymentContext context) {
+ for (Sniffer sniffer : snifferCol) {
+ String[] incompatTypes = sniffer.getIncompatibleSnifferTypes();
+ if (incompatTypes==null)
+ return;
+ for (String type : incompatTypes) {
+ for (Sniffer sniffer2 : snifferCol) {
+ if (sniffer2.getModuleType().equals(type)) {
+ throw new IllegalArgumentException(
+ localStrings.getLocalString(
+ "invalidarchivepackaging",
+ "Invalid archive packaging {2}",
+ sniffer.getModuleType(), type,
+ context.getSourceDir().getPath()));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/StAXParserFactory.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/StAXParserFactory.java
new file mode 100644
index 0000000..6567ff1
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/StAXParserFactory.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import javax.xml.stream.XMLInputFactory;
+
+import org.glassfish.hk2.api.Factory;
+import org.glassfish.hk2.api.PerLookup;
+
+/**
+ * Allow people to inject {@link XMLInputFactory} via {@link Inject}.
+ *
+ * <p>
+ * Component instantiation happens only when someone requests {@link XMLInputFactory},
+ * so this is as lazy as it gets.
+ *
+ * <p>
+ * TODO: if we need to let people choose StAX implementation, this is the place to do it.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+@Service
+@Singleton
+public class StAXParserFactory implements Factory<XMLInputFactory> {
+
+ /* (non-Javadoc)
+ * @see org.glassfish.hk2.api.Factory#provide()
+ */
+ @Override @PerLookup
+ public XMLInputFactory provide() {
+ // In JDK 1.6, StAX is part of JRE, so we use no argument variant of
+ // newInstance(), where as on JDK 1.5, we use two argument version of
+ // newInstance() so that we can pass the classloader that loads
+ // XMLInputFactory to load the factory, otherwise by default StAX uses
+ // Thread's context class loader to locate the factory. See:
+ // https://glassfish.dev.java.net/issues/show_bug.cgi?id=6428
+ return XMLInputFactory.class.getClassLoader() == null ?
+ XMLInputFactory.newInstance() :
+ XMLInputFactory.newInstance(XMLInputFactory.class.getName(),
+ XMLInputFactory.class.getClassLoader());
+ }
+
+ /* (non-Javadoc)
+ * @see org.glassfish.hk2.api.Factory#dispose(java.lang.Object)
+ */
+ @Override
+ public void dispose(XMLInputFactory instance) {
+
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SystemTasks.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SystemTasks.java
new file mode 100644
index 0000000..37aceb7
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SystemTasks.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+
+import org.jvnet.hk2.annotations.Contract;
+
+
+/**
+ * Interface for service to take care of vm related tasks.
+ *
+ * @author Tom Beerbower
+ */
+@Contract
+public interface SystemTasks {
+
+ /**
+ * Write the process ID to a file.
+ */
+ public void writePidFile();
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SystemTasksImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SystemTasksImpl.java
new file mode 100644
index 0000000..650ab28
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SystemTasksImpl.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.config.serverbeans.Cluster;
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.Configs;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.config.serverbeans.Server;
+import com.sun.enterprise.config.serverbeans.SystemProperty;
+import com.sun.enterprise.util.io.FileUtils;
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.internal.api.InitRunLevel;
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import com.sun.enterprise.universal.i18n.LocalStringsImpl;
+import com.sun.enterprise.universal.process.ProcessUtils;
+import com.sun.enterprise.util.net.NetUtils;
+import com.sun.enterprise.util.SystemPropertyConstants;
+import com.sun.appserv.server.util.Version;
+import com.sun.enterprise.universal.io.SmartFile;
+
+import org.jvnet.hk2.annotations.Optional;
+import org.glassfish.hk2.api.PostConstruct;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.config.support.TranslatedConfigView;
+import org.glassfish.api.admin.ServerEnvironment;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.logging.Logger;
+import java.util.logging.Level;
+import org.glassfish.kernel.KernelLoggerInfo;
+
+/**
+ * Init run level service to take care of vm related tasks.
+ *
+ * @author Jerome Dochez
+ * @author Byron Nevins
+ */
+// TODO: eventually use CageBuilder so that this gets triggered when JavaConfig enters Habitat.
+@Service
+@RunLevel( value=InitRunLevel.VAL, mode=RunLevel.RUNLEVEL_MODE_NON_VALIDATING)
+public class SystemTasksImpl implements SystemTasks, PostConstruct {
+
+ // in embedded environment, JavaConfig is pointless, so make this optional
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) @Optional
+
+ JavaConfig javaConfig;
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Server server;
+
+ @Inject
+ Domain domain;
+
+ Logger _logger = KernelLoggerInfo.getLogger();
+
+ private final static LocalStringsImpl strings = new LocalStringsImpl(SystemTasks.class);
+
+ @Override
+ public void postConstruct() {
+ setVersion();
+ setSystemPropertiesFromEnv();
+ setSystemPropertiesFromDomainXml();
+ resolveJavaConfig();
+ _logger.fine("SystemTasks: loaded server named: " + server.getName());
+ }
+
+ @Override
+ public void writePidFile() {
+ File pidFile = null;
+
+ try {
+ pidFile = SmartFile.sanitize(getPidFile());
+ File pidFileCopy = new File(pidFile.getPath() + ".prev");
+ String pidString = getPidString();
+ FileUtils.writeStringToFile(pidString, pidFile);
+ FileUtils.writeStringToFile(pidString, pidFileCopy);
+ }
+ catch (PidException pe) {
+ _logger.warning(pe.getMessage());
+ }
+ catch (Exception e) {
+ _logger.warning(strings.get("internal_error", e));
+ }
+ finally {
+ if (pidFile != null) {
+ pidFile.deleteOnExit();
+ }
+ }
+ }
+
+ private void setVersion() {
+ System.setProperty("glassfish.version", Version.getFullVersion());
+ }
+
+ /*
+ * Here is where we make the change Post-TP2 to *not* use JVM System Properties
+ */
+ private void setSystemProperty(String name, String value) {
+ System.setProperty(name, value);
+ }
+
+ private void setSystemPropertiesFromEnv() {
+ // adding our version of some system properties.
+ setSystemProperty(SystemPropertyConstants.JAVA_ROOT_PROPERTY, System.getProperty("java.home"));
+
+ String hostname = "localhost";
+
+
+ try {
+ // canonical name checks to make sure host is proper
+ hostname = NetUtils.getCanonicalHostName();
+
+
+ }
+ catch (Exception ex) {
+ if (_logger != null) {
+ _logger.log(Level.SEVERE, KernelLoggerInfo.exceptionHostname, ex);
+ }
+ }
+ if (hostname != null) {
+ setSystemProperty(SystemPropertyConstants.HOST_NAME_PROPERTY, hostname);
+ }
+ }
+
+ private void setSystemPropertiesFromDomainXml() {
+ // precedence order from high to low
+ // 0. server
+ // 1. cluster
+ // 2. <server>-config or <cluster>-config
+ // 3. domain
+ // so we need to add System Properties in *reverse order* to get the
+ // right precedence.
+
+ List<SystemProperty> domainSPList = domain.getSystemProperty();
+ List<SystemProperty> configSPList = getConfigSystemProperties();
+ Cluster cluster = server.getCluster();
+ List<SystemProperty> clusterSPList = null;
+
+
+ if (cluster != null) {
+ clusterSPList = cluster.getSystemProperty();
+
+
+ }
+ List<SystemProperty> serverSPList = server.getSystemProperty();
+
+ setSystemProperties(
+ domainSPList);
+ setSystemProperties(
+ configSPList);
+
+
+ if (clusterSPList != null) {
+ setSystemProperties(clusterSPList);
+
+
+ }
+ setSystemProperties(serverSPList);
+ }
+
+ private List<SystemProperty> getConfigSystemProperties() {
+ try {
+ String configName = server.getConfigRef();
+ Configs configs = domain.getConfigs();
+ List<Config> configsList = configs.getConfig();
+ Config config = null;
+
+ for (Config c : configsList) {
+ if (c.getName().equals(configName)) {
+ config = c;
+ break;
+ }
+ }
+ return (List<SystemProperty>) (config != null ? config.getSystemProperty() : Collections.emptyList());
+ }
+ catch (Exception e) { //possible NPE if domain.xml has issues!
+ return Collections.emptyList();
+ }
+ }
+
+ private void resolveJavaConfig() {
+ if (javaConfig != null) {
+ Pattern p = Pattern.compile("-D([^=]*)=(.*)");
+
+ for (String jvmOption : javaConfig.getJvmOptions()) {
+ Matcher m = p.matcher(jvmOption);
+
+ if (m.matches()) {
+ setSystemProperty(m.group(1), TranslatedConfigView.getTranslatedValue(m.group(2)).toString());
+
+ if (_logger.isLoggable(Level.FINE)) {
+ _logger.fine("Setting " + m.group(1) + " = " + TranslatedConfigView.getTranslatedValue(m.group(2)));
+ }
+ }
+ }
+ }
+ }
+
+ private void setSystemProperties(List<SystemProperty> spList) {
+ for (SystemProperty sp : spList) {
+ String name = sp.getName();
+ String value = sp.getValue();
+
+ if (ok(name)) {
+ setSystemProperty(name, value);
+ }
+ }
+ }
+
+ private String getPidString() {
+ return "" + ProcessUtils.getPid();
+ }
+
+ private File getPidFile() throws PidException {
+ try {
+ String configDirString = System.getProperty(SystemPropertyConstants.INSTANCE_ROOT_PROPERTY);
+
+ if (!ok(configDirString))
+ throw new PidException(strings.get("internal_error",
+ "Null or empty value for the System Property: "
+ + SystemPropertyConstants.INSTANCE_ROOT_PROPERTY));
+
+ File configDir = new File(new File(configDirString), "config");
+
+ if (!configDir.isDirectory())
+ throw new PidException(strings.get("bad_config_dir", configDir));
+
+ File pidFile = new File(configDir, "pid");
+
+ if (pidFile.exists()) {
+ if (!pidFile.delete() || pidFile.exists()) {
+ throw new PidException(strings.get("cant_delete_pid_file", pidFile));
+ }
+ }
+ return pidFile;
+ }
+ catch (PidException pe) {
+ throw pe;
+ }
+ catch (Exception e) {
+ throw new PidException(e.getMessage());
+ }
+ }
+
+ private static boolean ok(String s) {
+ return s != null && s.length() > 0;
+ }
+
+ private static class PidException extends Exception {
+
+ public PidException(String s) {
+ super(s);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/UpgradeStartup.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/UpgradeStartup.java
new file mode 100644
index 0000000..9482340
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/UpgradeStartup.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import com.sun.enterprise.module.bootstrap.ModuleStartup;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.v3.common.DoNothingActionReporter;
+import com.sun.enterprise.config.serverbeans.Applications;
+import com.sun.enterprise.config.serverbeans.Application;
+import com.sun.enterprise.config.serverbeans.Server;
+import com.sun.enterprise.config.serverbeans.ServerTags;
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.util.io.FileUtils;
+import com.sun.enterprise.util.StringUtils;
+import com.sun.enterprise.deploy.shared.ArchiveFactory;
+import org.glassfish.hk2.api.IterableProvider;
+import org.jvnet.hk2.annotations.Optional;
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jvnet.hk2.config.*;
+import org.glassfish.api.admin.CommandRunner;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.deployment.DeployCommandParameters;
+import org.glassfish.api.deployment.archive.ReadableArchive;
+import org.glassfish.api.deployment.archive.WritableArchive;
+import org.glassfish.api.ActionReport;
+import org.glassfish.deployment.common.DeploymentProperties;
+import org.glassfish.internal.api.*;
+
+import java.util.*;
+import java.util.jar.*;
+import java.util.logging.Logger;
+import java.util.logging.Level;
+import java.net.URISyntaxException;
+import java.net.URI;
+import java.io.*;
+import java.beans.PropertyVetoException;
+import org.glassfish.kernel.KernelLoggerInfo;
+
+/**
+ * Very simple ModuleStartup that basically force an immediate shutdown.
+ * When start() is invoked, the upgrade of the domain.xml has already been
+ * performed.
+ *
+ * @author Jerome Dochez
+ */
+@Service(name="upgrade")
+public class UpgradeStartup implements ModuleStartup {
+
+ @Inject
+ CommandRunner runner;
+
+ @Inject
+ AppServerStartup appservStartup;
+
+ @Inject
+ Applications applications;
+
+ @Inject
+ ArchiveFactory archiveFactory;
+
+ @Inject
+ ServerEnvironment env;
+
+ @Inject @Named( ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Server server;
+
+ @Inject
+ Domain domain;
+
+ @Inject
+ CommandRunner commandRunner;
+
+ @Inject @Optional
+ IterableProvider<DomainUpgrade> upgrades;
+
+ // we need to refine, a better logger should be used.
+ @Inject
+ Logger logger;
+
+ @Inject
+ private InternalSystemAdministrator kernelIdentity;
+
+ private final static String MODULE_TYPE = "moduleType";
+
+ private final static String J2EE_APPS = "j2ee-apps";
+ private final static String J2EE_MODULES = "j2ee-modules";
+
+ private final static String DOMAIN_TARGET = "domain";
+
+ private final static String SIGNATURE_TYPES_PARAM = "-signatureTypes";
+
+ private List<String> sigTypeList = new ArrayList<String>();
+
+ public void setStartupContext(StartupContext startupContext) {
+ appservStartup.setStartupContext(startupContext);
+ }
+
+ // do nothing, just return, at the time the upgrade service has
+ // run correctly.
+ public void start() {
+
+ // we need to disable all the applications before starting server
+ // so the applications will not get loaded before redeployment
+ // store the list of previous enabled applications
+ // so we can reset these applications back to enabled after
+ // redeployment
+ List<Application> enabledApps = new ArrayList<Application>();
+ List<String> enabledAppNames = new ArrayList<String>();
+
+ for (Application app : domain.getApplications().getApplications()) {
+ logger.log(Level.INFO, "app " + app.getName() + " is " + app.getEnabled() + " resulting in " + Boolean.parseBoolean(app.getEnabled()));
+ if (Boolean.parseBoolean(app.getEnabled())) {
+ logger.log(Level.INFO, "Disabling application " + app.getName());
+ enabledApps.add(app);
+ enabledAppNames.add(app.getName());
+ }
+ }
+
+ if (enabledApps.size()>0) {
+ try {
+ ConfigSupport.apply(new ConfigCode() {
+ public Object run(ConfigBeanProxy... configBeanProxies) throws PropertyVetoException, TransactionFailure {
+ for (ConfigBeanProxy proxy : configBeanProxies) {
+ Application app = (Application) proxy;
+ app.setEnabled(Boolean.FALSE.toString());
+ }
+ return null;
+ }
+ }, enabledApps.toArray(new Application[enabledApps.size()]));
+ } catch(TransactionFailure tf) {
+ logger.log(Level.SEVERE, "Exception while disabling applications", tf);
+ return;
+ }
+ }
+
+ // start the application server
+ appservStartup.start();
+
+ initializeSigTypeList();
+
+ // redeploy all existing applications
+ for (Application app : applications.getApplications()) {
+ // we don't need to redeploy lifecycle modules
+ if (Boolean.valueOf(app.getDeployProperties().getProperty
+ (ServerTags.IS_LIFECYCLE))) {
+ continue;
+ }
+ logger.log(Level.INFO, "Redeploy application " + app.getName() + " located at " + app.getLocation());
+ // we let upgrade proceed even if one application
+ // failed to redeploy
+ redeployApp(app);
+ }
+
+ // re-enables all applications.
+ // we need to use the names in the enabledAppNames to find all
+ // the application refs that need to be re-enabled
+ // as the previous application collected not longer exist
+ // after redeployment
+ if (enabledAppNames.size()>0) {
+ for (Application app : domain.getApplications().getApplications()) {
+ if (enabledAppNames.contains(app.getName())) {
+ logger.log(Level.INFO, "Enabling application " + app.getName());
+ try {
+ ConfigSupport.apply(new SingleConfigCode<Application>() {
+ public Object run(Application param) throws PropertyVetoException, TransactionFailure {
+ if (!Boolean.parseBoolean(param.getEnabled())) {
+ param.setEnabled(Boolean.TRUE.toString());
+ }
+ return null;
+ }
+ }, app);
+ } catch(TransactionFailure tf) {
+ logger.log(Level.SEVERE, "Exception while disabling applications", tf);
+ return;
+ }
+ }
+ }
+ }
+
+ // clean up leftover directories
+ cleanupLeftOverDirectories();
+
+ // stop-the server.
+ KernelLoggerInfo.getLogger().info(KernelLoggerInfo.exitUpgrade);
+ try {
+ Thread.sleep(3000);
+ if (runner!=null) {
+ runner.getCommandInvocation("stop-domain", new DoNothingActionReporter(), kernelIdentity.getSubject()).execute();
+ }
+
+ } catch (InterruptedException e) {
+ KernelLoggerInfo.getLogger().log(Level.SEVERE, KernelLoggerInfo.exceptionUpgrade, e);
+ }
+
+ }
+
+ public void stop() {
+ appservStartup.stop();
+ }
+
+ private void cleanupLeftOverDirectories() {
+ // 1. remove applications/j2ee-apps(modules) directory
+ File oldJ2eeAppsRepository = new File(
+ env.getApplicationRepositoryPath(), J2EE_APPS);
+ FileUtils.whack(oldJ2eeAppsRepository);
+ File oldJ2eeModulesRepository = new File(
+ env.getApplicationRepositoryPath(), J2EE_MODULES);
+ FileUtils.whack(oldJ2eeModulesRepository);
+
+ // 2. remove generated/xml/j2ee-apps(modules) directory
+ File oldJ2eeAppsGeneratedXMLDir = new File(
+ env.getApplicationGeneratedXMLPath(), J2EE_APPS);
+ FileUtils.whack(oldJ2eeAppsGeneratedXMLDir);
+ File oldJ2eeModulesGeneratedXMLDir = new File(
+ env.getApplicationGeneratedXMLPath(), J2EE_MODULES);
+ FileUtils.whack(oldJ2eeModulesGeneratedXMLDir);
+
+ // 3. remove generated/ejb/j2ee-apps(modules) directory
+ File oldJ2eeAppsEJBStubDir = new File(
+ env.getApplicationEJBStubPath(), J2EE_APPS);
+ FileUtils.whack(oldJ2eeAppsEJBStubDir);
+ File oldJ2eeModulesEJBStubDir = new File(
+ env.getApplicationEJBStubPath(), J2EE_MODULES);
+ FileUtils.whack(oldJ2eeModulesEJBStubDir);
+
+ // 4. clean up generated/jsp/j2ee-apps(modules) directory
+ File oldJ2eeAppsJSPCompileDir = new File(
+ env.getApplicationCompileJspPath(), J2EE_APPS);
+ FileUtils.whack(oldJ2eeAppsJSPCompileDir);
+ File oldJ2eeModulesJSPCompileDir = new File(
+ env.getApplicationCompileJspPath(), J2EE_MODULES);
+ FileUtils.whack(oldJ2eeModulesJSPCompileDir);
+
+ // 5. clean up old system apps policy files
+ File policyRootDir = env.getApplicationPolicyFilePath();
+ File adminapp = new File(policyRootDir, "adminapp");
+ FileUtils.whack(adminapp);
+ File admingui = new File(policyRootDir, "admingui");
+ FileUtils.whack(admingui);
+ File ejbtimer = new File(policyRootDir, "__ejb_container_timer_app");
+ FileUtils.whack(ejbtimer);
+ File mejbapp = new File(policyRootDir, "MEjbApp");
+ FileUtils.whack(mejbapp);
+ File wstx = new File(policyRootDir, "WSTXServices");
+ FileUtils.whack(wstx);
+ File jwsappclient = new File(policyRootDir, "__JWSappclients");
+ FileUtils.whack(jwsappclient);
+ }
+
+ private boolean redeployApp(Application app) {
+ // we don't need to redeploy any v3 type application
+ if (app.getModule().size() > 0 ) {
+ logger.log(Level.INFO, "Skip redeploying v3 type application " +
+ app.getName());
+ return true;
+ }
+
+ // populate the params and properties from application element first
+ DeployCommandParameters deployParams = app.getDeployParameters(null);
+
+ // for archive deployment, let's repackage the archive and redeploy
+ // that way
+ // we cannot just directory redeploy the archive deployed apps in
+ // v2->v3 upgrade as the repository layout was different in v2
+ // we should not have to repackage for any upgrade from v3
+ if (! Boolean.valueOf(app.getDirectoryDeployed())) {
+ File repackagedFile = null;
+ try {
+ repackagedFile = repackageArchive(app);
+ } catch (IOException ioe) {
+ logger.log(Level.SEVERE, "Repackaging of application " + app.getName() + " failed: " + ioe.getMessage(), ioe);
+ return false;
+ }
+ if (repackagedFile == null) {
+ logger.log(Level.SEVERE, "Repackaging of application " + app.getName() + " failed.");
+ return false;
+ }
+ logger.log(Level.INFO, "Repackaged application " + app.getName()
+ + " at " + repackagedFile.getPath());
+ deployParams.path = repackagedFile;
+ }
+
+ deployParams.properties = app.getDeployProperties();
+ // remove the marker properties so they don't get carried over
+ // through redeployment
+ deployParams.properties.remove(MODULE_TYPE);
+ // add the compatibility property so the applications are
+ // upgraded/redeployed in a backward compatible way
+ deployParams.properties.setProperty(
+ DeploymentProperties.COMPATIBILITY, "v2");
+
+ // now override the ones needed for the upgrade
+ deployParams.enabled = null;
+ deployParams.force = true;
+ deployParams.dropandcreatetables = false;
+ deployParams.createtables = false;
+ deployParams.target = DOMAIN_TARGET;
+
+ ActionReport report = new DoNothingActionReporter();
+ commandRunner.getCommandInvocation("deploy", report, kernelIdentity.getSubject()).parameters(deployParams).execute();
+
+ // should we delete the temp file after we are done
+ // it seems it might be useful to keep it around for debugging purpose
+
+ if (report.getActionExitCode().equals(ActionReport.ExitCode.FAILURE)) {
+ logger.log(Level.SEVERE, "Redeployment of application " + app.getName() + " failed: " + report.getMessage() + "\nPlease redeploy " + app.getName() + " manually.", report.getFailureCause());
+ return false;
+ }
+ return true;
+ }
+
+ private File repackageArchive(Application app) throws IOException {
+ URI uri = null;
+ try {
+ uri = new URI(app.getLocation());
+ } catch (URISyntaxException e) {
+ logger.log(Level.SEVERE, e.getMessage(), e);
+ }
+
+ if (uri == null) {
+ return null;
+ }
+
+ Properties appProperties = app.getDeployProperties();
+ String moduleType = appProperties.getProperty(MODULE_TYPE);
+ String suffix = getSuffixFromType(moduleType);
+ if (suffix == null) {
+ suffix = ".jar";
+ }
+ File repositoryDir = new File(uri);
+
+ // get temporary file directory of the system and set targetDir to it
+ File tmp = File.createTempFile("upgrade", null);
+ String targetParentDir = tmp.getParent();
+ boolean isDeleted = tmp.delete();
+ if (!isDeleted) {
+ logger.log(Level.WARNING, "Error in deleting file " + tmp.getAbsolutePath());
+ }
+
+ if (moduleType.equals(ServerTags.J2EE_APPLICATION)) {
+ return repackageApplication(repositoryDir, targetParentDir, suffix);
+ } else {
+ return repackageStandaloneModule(repositoryDir, targetParentDir, suffix);
+ }
+ }
+
+ private File repackageApplication(File appDir,
+ String targetParentDir, String suffix) throws IOException {
+ String appName = appDir.getName();
+
+ ReadableArchive source = archiveFactory.openArchive(appDir);
+
+ File tempEar = new File(targetParentDir, appName + suffix);
+
+ if (tempEar.exists()) {
+ boolean isDeleted = tempEar.delete();
+ if (!isDeleted) {
+ logger.log(Level.WARNING, "Error in deleting file " + tempEar.getAbsolutePath());
+ }
+ }
+
+ WritableArchive target = archiveFactory.createArchive("jar", tempEar);
+
+ Collection<String> directoryEntries = source.getDirectories();
+ List<String> subModuleEntries = new ArrayList<String>();
+ List<String> entriesToExclude = new ArrayList<String>();
+
+ // first put all the sub module jars to the target archive
+ for (String directoryEntry : directoryEntries) {
+ if (directoryEntry.endsWith("_jar") ||
+ directoryEntry.endsWith("_war") ||
+ directoryEntry.endsWith("_rar")) {
+ subModuleEntries.add(directoryEntry);
+ File moduleJar = processModule(new File(
+ appDir, directoryEntry), targetParentDir, null);
+ OutputStream os = null;
+ InputStream is = new BufferedInputStream(
+ new FileInputStream(moduleJar));
+ try {
+ os = target.putNextEntry(moduleJar.getName());
+ FileUtils.copy(is, os, moduleJar.length());
+ } finally {
+ if (os!=null) {
+ target.closeEntry();
+ }
+ is.close();
+ }
+ }
+ }
+
+ // now find all the entries we should exclude to copy to the target
+ // basically all sub module entries should be excluded
+ for (String subModuleEntry : subModuleEntries) {
+ Enumeration<String> ee = source.entries(subModuleEntry);
+ while (ee.hasMoreElements()) {
+ String eeEntryName = ee.nextElement();
+ entriesToExclude.add(eeEntryName);
+ }
+ }
+
+ // now copy the rest of the entries
+ Enumeration<String> e = source.entries();
+ while (e.hasMoreElements()) {
+ String entryName = e.nextElement();
+ if (! entriesToExclude.contains(entryName)) {
+ InputStream sis = source.getEntry(entryName);
+ if (isSigFile(entryName)) {
+ logger.log(Level.INFO, "Excluding signature file: "
+ + entryName + " from repackaged application: " +
+ appName + "\n");
+ continue;
+ }
+ if (sis != null) {
+ InputStream is = new BufferedInputStream(sis);
+ OutputStream os = null;
+ try {
+ os = target.putNextEntry(entryName);
+ FileUtils.copy(is, os, source.getEntrySize(entryName));
+ } finally {
+ if (os!=null) {
+ target.closeEntry();
+ }
+ is.close();
+ }
+ }
+ }
+ }
+
+ // last is manifest if existing.
+ Manifest m = source.getManifest();
+ if (m!=null) {
+ processManifest(m, appName);
+ OutputStream os = target.putNextEntry(JarFile.MANIFEST_NAME);
+ m.write(os);
+ target.closeEntry();
+ }
+
+ source.close();
+ target.close();
+
+ return tempEar;
+ }
+
+ private File repackageStandaloneModule(File moduleDirName,
+ String targetParentDir, String suffix) throws IOException {
+ return processModule(moduleDirName, targetParentDir, suffix);
+ }
+
+ // repackage a module and return it as a jar file
+ private File processModule(File moduleDir, String targetParentDir,
+ String suffix) throws IOException {
+
+ String moduleName = moduleDir.getName();
+
+ // sub module in ear case
+ if (moduleName.endsWith("_jar") || moduleName.endsWith("_war") || moduleName.endsWith("_rar")) {
+ suffix = "." + moduleName.substring(moduleName.length() - 3);
+ moduleName = moduleName.substring(0, moduleName.lastIndexOf('_'));
+ }
+
+ ReadableArchive source = archiveFactory.openArchive(moduleDir);
+
+ File tempJar = new File(targetParentDir, moduleName + suffix);
+
+ if (tempJar.exists()) {
+ boolean isDeleted = tempJar.delete();
+ if ( !isDeleted) {
+ logger.log(Level.WARNING, "Error in deleting file " + tempJar.getAbsolutePath());
+ }
+ }
+
+ WritableArchive target = archiveFactory.createArchive("jar", tempJar);
+
+ Enumeration<String> e = source.entries();
+ while (e.hasMoreElements()) {
+ String entryName = e.nextElement();
+ if (isSigFile(entryName)) {
+ logger.log(Level.INFO, "Excluding signature file: "
+ + entryName + " from repackaged module: " + moduleName +
+ "\n");
+ continue;
+ }
+ InputStream sis = source.getEntry(entryName);
+ if (sis != null) {
+ InputStream is = new BufferedInputStream(sis);
+ OutputStream os = null;
+ try {
+ os = target.putNextEntry(entryName);
+ FileUtils.copy(is, os, source.getEntrySize(entryName));
+ } finally {
+ if (os!=null) {
+ target.closeEntry();
+ }
+ is.close();
+ }
+ }
+ }
+
+ // last is manifest if existing.
+ Manifest m = source.getManifest();
+ if (m!=null) {
+ processManifest(m, moduleName);
+ OutputStream os = target.putNextEntry(JarFile.MANIFEST_NAME);
+ m.write(os);
+ target.closeEntry();
+ }
+
+ source.close();
+ target.close();
+
+ return tempJar;
+ }
+
+ private String getSuffixFromType(String moduleType) {
+ if (moduleType == null) {
+ return null;
+ }
+ if (moduleType.equals(ServerTags.CONNECTOR_MODULE)) {
+ return ".rar";
+ }
+ if (moduleType.equals(ServerTags.EJB_MODULE)) {
+ return ".jar";
+ }
+ if (moduleType.equals(ServerTags.WEB_MODULE)) {
+ return ".war";
+ }
+ if (moduleType.equals(ServerTags.APPCLIENT_MODULE)) {
+ return ".jar";
+ }
+ if (moduleType.equals(ServerTags.J2EE_APPLICATION)) {
+ return ".ear";
+ }
+ return null;
+ }
+
+ private void initializeSigTypeList() {
+ String sigTypesParam = env.getStartupContext().getArguments().getProperty(SIGNATURE_TYPES_PARAM);
+ if (sigTypesParam != null) {
+ sigTypeList = StringUtils.parseStringList(sigTypesParam, ",");
+ }
+ sigTypeList.add(".SF");
+ sigTypeList.add(".sf");
+ sigTypeList.add(".RSA");
+ sigTypeList.add(".rsa");
+ sigTypeList.add(".DSA");
+ sigTypeList.add(".dsa");
+ sigTypeList.add(".PGP");
+ sigTypeList.add(".pgp");
+ }
+
+ private boolean isSigFile(String entryName) {
+ for (String sigType : sigTypeList) {
+ if (entryName.endsWith(sigType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void processManifest(Manifest m, String moduleName) {
+ // remove signature related entries from the file
+ Map<String, Attributes> entries = m.getEntries();
+ Iterator<Map.Entry<String, Attributes>> entryItr = entries.entrySet().iterator();
+ while (entryItr.hasNext()) {
+ Attributes attr = entryItr.next().getValue();
+ Iterator<Map.Entry<Object, Object>> attrItr = attr.entrySet().iterator();
+ while (attrItr.hasNext()) {
+ Object attrKey = attrItr.next().getKey();
+ if (attrKey instanceof Attributes.Name) {
+ Attributes.Name attrKey2 = (Attributes.Name) attrKey;
+ if (attrKey2.toString().trim().equals("Digest-Algorithms")
+ || attrKey2.toString().indexOf("-Digest") != -1) {
+ logger.log(Level.INFO, "Removing signature attribute "
+ + attrKey2 + " from manifest in " +
+ moduleName + "\n");
+ attrItr.remove();
+ }
+ }
+ }
+ if (attr.size() == 0) {
+ entryItr.remove();
+ }
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ADBAwareHttpHandler.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ADBAwareHttpHandler.java
new file mode 100644
index 0000000..88c8c93
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ADBAwareHttpHandler.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.grizzly.Grizzly;
+import org.glassfish.grizzly.http.Method;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.StaticHttpHandler;
+import org.glassfish.grizzly.http.server.util.AlternateDocBase;
+import org.glassfish.grizzly.http.util.Header;
+import org.glassfish.grizzly.http.util.HttpStatus;
+
+import static org.glassfish.grizzly.http.server.StaticHttpHandlerBase.sendFile;
+
+/**
+ * {@link StaticHttpHandler}, which additionally can check registered
+ * {@link AlternateDocBase}s to serve requested resources.
+ *
+ * @author Alexey Stashok
+ */
+public class ADBAwareHttpHandler extends StaticHttpHandler {
+ private static final Logger LOGGER = Grizzly.logger(ADBAwareHttpHandler.class);
+
+ private final List<AlternateDocBase> alternateDocBases =
+ new ArrayList<AlternateDocBase>();
+
+ public ADBAwareHttpHandler() {
+ // make sure the default "." docRoot won't be added
+ super((Set<String>) null);
+ }
+
+ /**
+ * Add {@link AlternateDocBase} to be checked for requested resources.
+ *
+ * @param urlPattern
+ * @param docBase absolute path
+ */
+ public void addAlternateDocBase(final String urlPattern,
+ final String docBase) {
+
+ if (urlPattern == null) {
+ throw new IllegalArgumentException("The urlPattern argument can't be null");
+ } else if (docBase == null) {
+ throw new IllegalArgumentException("The docBase argument can't be null");
+ }
+
+ AlternateDocBase alternateDocBase = new AlternateDocBase();
+ alternateDocBase.setUrlPattern(urlPattern);
+ alternateDocBase.setDocBase(docBase);
+ alternateDocBase.setBasePath(getBasePath(docBase));
+
+ alternateDocBases.add(alternateDocBase);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean handle(final String uri,
+ final Request request, final Response response) throws Exception {
+ final File file = lookupInADB(uri);
+ if (file != null) {
+ serveFile(file, request, response);
+ return true;
+ }
+
+ return super.handle(uri, request, response);
+ }
+
+ /**
+ * Get base path.
+ */
+ private String getBasePath(final String docBase) {
+ return new File(docBase).getAbsolutePath();
+ }
+
+ private void serveFile(final File file, final Request request,
+ final Response response) throws IOException {
+ // If it's not HTTP GET - return method is not supported status
+ if (!Method.GET.equals(request.getMethod())) {
+ if (LOGGER.isLoggable(Level.FINE)) {
+ LOGGER.log(Level.FINE, "File found {0}, but HTTP method {1} is not allowed",
+ new Object[] {file, request.getMethod()});
+ }
+ response.setStatus(HttpStatus.METHOD_NOT_ALLOWED_405);
+ response.setHeader(Header.Allow, "GET");
+ return;
+ }
+
+ pickupContentType(response, file.getPath());
+
+ addToFileCache(request, response, file);
+ sendFile(response, file);
+ }
+
+ private File lookupInADB(final String uri) {
+ final AlternateDocBase adb = AlternateDocBase.findMatch(
+ uri, alternateDocBases);
+ if (adb != null) {
+ File file = new File(adb.getBasePath(), uri);
+ boolean exists = file.exists();
+ boolean isDirectory = file.isDirectory();
+
+ if (exists && isDirectory) {
+ file = new File(file, "/index.html");
+ exists = file.exists();
+ isDirectory = file.isDirectory();
+ }
+
+ if (exists && !isDirectory) {
+ return file;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ContainerMapper.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ContainerMapper.java
new file mode 100644
index 0000000..eef7e75
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ContainerMapper.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import java.io.CharConversionException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.glassfish.api.container.Adapter;
+import org.glassfish.api.container.Sniffer;
+import org.glassfish.api.deployment.ApplicationContainer;
+import org.glassfish.api.logging.LogHelper;
+import org.glassfish.grizzly.config.ContextRootInfo;
+import org.glassfish.grizzly.config.GrizzlyListener;
+import org.glassfish.grizzly.http.server.AfterServiceListener;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.HttpHandlerChain;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.Note;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.util.Mapper;
+import org.glassfish.grizzly.http.server.util.MappingData;
+import org.glassfish.grizzly.http.util.CharChunk;
+import org.glassfish.grizzly.http.util.DataChunk;
+import org.glassfish.grizzly.http.util.MimeType;
+import org.glassfish.internal.grizzly.ContextMapper;
+import org.glassfish.kernel.KernelLoggerInfo;
+
+/**
+ * Container's mapper which maps {@link ByteBuffer} bytes representation to an {@link HttpHandler}, {@link
+ * ApplicationContainer} and ProtocolFilter chain. The mapping result is stored inside {@link MappingData} which
+ * is eventually shared with the CoyoteAdapter, which is the entry point with the Catalina Servlet Container.
+ *
+ * @author Jeanfrancois Arcand
+ * @author Alexey Stashok
+ */
+@SuppressWarnings({"NonPrivateFieldAccessedInSynchronizedContext"})
+public class ContainerMapper extends ADBAwareHttpHandler {
+
+ private static final Logger LOGGER = KernelLoggerInfo.getLogger();
+ private final static String ROOT = "";
+ private ContextMapper mapper;
+ private final GrizzlyListener listener;
+ private String defaultHostName = "server";
+ private final GrizzlyService grizzlyService;
+ protected final static Note<MappingData> MAPPING_DATA =
+ Request.<MappingData>createNote("MappingData");
+ // Make sure this value is always aligned with {@link org.apache.catalina.connector.CoyoteAdapter}
+ // (@see org.apache.catalina.connector.CoyoteAdapter)
+ private final static Note<DataChunk> DATA_CHUNK =
+ Request.<DataChunk>createNote("DataChunk");
+ private final ReentrantReadWriteLock mapperLock;
+
+
+ private static final AfterServiceListener afterServiceListener =
+ new AfterServiceListenerImpl();
+ /**
+ * Are we running multiple {@ Adapter} or {@link HttpHandlerChain}
+ */
+ private boolean mapMultipleAdapter;
+
+ public ContainerMapper(final GrizzlyService service,
+ final GrizzlyListener grizzlyListener) {
+ listener = grizzlyListener;
+ grizzlyService = service;
+ mapperLock = service.obtainMapperLock();
+ }
+
+ /**
+ * Set the default host that will be used when we map.
+ *
+ * @param defaultHost
+ */
+ protected void setDefaultHost(String defaultHost) {
+ mapperLock.writeLock().lock();
+ try {
+ defaultHostName = defaultHost;
+ } finally {
+ mapperLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Set the {@link ContextMapper} instance used for mapping the container and its associated {@link Adapter}.
+ *
+ * @param mapper
+ */
+ protected void setMapper(ContextMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ /**
+ * Configure the {@link ContextMapper}.
+ */
+ protected void configureMapper() {
+ mapperLock.writeLock().lock();
+
+ try {
+ mapper.setDefaultHostName(defaultHostName);
+ mapper.addHost(defaultHostName, new String[]{}, null);
+ mapper.addContext(defaultHostName, ROOT,
+ new ContextRootInfo(this, null),
+ new String[]{"index.html", "index.htm"}, null);
+ // Container deployed have the right to override the default setting.
+ Mapper.setAllowReplacement(true);
+ } finally {
+ mapperLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Map the request to its associated {@link Adapter}.
+ *
+ * @param request
+ * @param response
+ *
+ * @throws IOException
+ */
+ @Override
+ public void service(final Request request, final Response response) throws Exception {
+ try {
+ request.addAfterServiceListener(afterServiceListener);
+
+ final Callable handler = lookupHandler(request, response);
+ handler.call();
+ } catch (Exception ex) {
+ try {
+ if (LOGGER.isLoggable(Level.WARNING)) {
+ LogHelper.log(LOGGER, Level.WARNING, KernelLoggerInfo.exceptionMapper, ex,
+ request.getRequest().getRequestURIRef().getDecodedRequestURIBC());
+ }
+
+ response.sendError(500);
+ } catch (Exception ex2) {
+ if (LOGGER.isLoggable(Level.WARNING)) {
+ LOGGER.log(Level.WARNING, KernelLoggerInfo.exceptionMapper2, ex2);
+ }
+ if (ex2 instanceof CharConversionException) {
+ response.sendError(500);
+ }
+ }
+ }
+ }
+
+ private Callable lookupHandler(final Request request,
+ final Response response) throws CharConversionException, Exception {
+ MappingData mappingData;
+
+ mapperLock.readLock().lock();
+
+ try {
+ // If we have only one Adapter deployed, invoke that Adapter directly.
+ if (!mapMultipleAdapter) {
+ // Remove the MappingData as we might delegate the request
+ // to be serviced directly by the WebContainer
+ final HttpHandler httpHandler = mapper.getHttpHandler();
+ if (httpHandler != null) {
+ request.setNote(MAPPING_DATA, null);
+// httpHandler.service(request, response);
+// return;
+ return new HttpHandlerCallable(httpHandler,
+ request, response);
+ }
+ }
+
+ final DataChunk decodedURI = request.getRequest()
+ .getRequestURIRef().getDecodedRequestURIBC(isAllowEncodedSlash());
+
+ mappingData = request.getNote(MAPPING_DATA);
+ if (mappingData == null) {
+ mappingData = new MappingData();
+ request.setNote(MAPPING_DATA, mappingData);
+ } else {
+ mappingData.recycle();
+ }
+ HttpHandler httpHandler;
+
+ final CharChunk decodedURICC = decodedURI.getCharChunk();
+ final int semicolon = decodedURICC.indexOf(';', 0);
+
+ // Map the request without any trailling.
+ httpHandler = mapUriWithSemicolon(request, decodedURI,
+ semicolon, mappingData);
+ if (httpHandler == null || httpHandler instanceof ContainerMapper) {
+ String ext = decodedURI.toString();
+ String type = "";
+ if (ext.lastIndexOf(".") > 0) {
+ ext = "*" + ext.substring(ext.lastIndexOf("."));
+ type = ext.substring(ext.lastIndexOf(".") + 1);
+ }
+
+ if (!MimeType.contains(type) && !"/".equals(ext)) {
+ initializeFileURLPattern(ext);
+ mappingData.recycle();
+ httpHandler = mapUriWithSemicolon(request, decodedURI,
+ semicolon, mappingData);
+ } else {
+// super.service(request, response);
+// return;
+ return new SuperCallable(request, response);
+ }
+ }
+
+ if (LOGGER.isLoggable(Level.FINE)) {
+ LOGGER.log(Level.FINE, "Request: {0} was mapped to Adapter: {1}",
+ new Object[]{decodedURI.toString(), httpHandler});
+ }
+
+ // The Adapter used for servicing static pages doesn't decode the
+ // request by default, hence do not pass the undecoded request.
+ if (httpHandler == null || httpHandler instanceof ContainerMapper) {
+// super.service(request, response);
+ return new SuperCallable(request, response);
+ } else {
+// httpHandler.service(request, response);
+ return new HttpHandlerCallable(httpHandler, request, response);
+ }
+ } finally {
+ mapperLock.readLock().unlock();
+ }
+ }
+
+ private void initializeFileURLPattern(String ext) {
+ for (Sniffer sniffer : grizzlyService.getHabitat().<Sniffer>getAllServices(Sniffer.class)) {
+ boolean match = false;
+ if (sniffer.getURLPatterns() != null) {
+
+ for (String pattern : sniffer.getURLPatterns()) {
+ if (pattern.equalsIgnoreCase(ext)) {
+ match = true;
+ break;
+ }
+ }
+
+ HttpHandler httpHandler;
+ if (match) {
+ httpHandler = grizzlyService.getHabitat().getService(SnifferAdapter.class);
+ ((SnifferAdapter) httpHandler).initialize(sniffer, this);
+ ContextRootInfo c = new ContextRootInfo(httpHandler, null);
+
+ mapperLock.readLock().unlock();
+ mapperLock.writeLock().lock();
+ try {
+ for (String pattern : sniffer.getURLPatterns()) {
+ for (String host : grizzlyService.hosts) {
+ mapper.addWrapper(host, ROOT, pattern, c,
+ "*.jsp".equals(pattern) || "*.jspx".equals(pattern));
+ }
+ }
+ } finally {
+ mapperLock.readLock().lock();
+ mapperLock.writeLock().unlock();
+ }
+
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Maps the decodedURI to the corresponding Adapter, considering that URI
+ * may have a semicolon with extra data followed, which shouldn't be a part
+ * of mapping process.
+ *
+ * @param req HTTP request
+ * @param decodedURI URI
+ * @param semicolonPos semicolon position. Might be <tt>0</tt> if position wasn't resolved yet (so it will be resolved in the method), or <tt>-1</tt> if there is no semicolon in the URI.
+ * @param mappingData
+ * @return
+ * @throws Exception
+ */
+ final HttpHandler mapUriWithSemicolon(final Request req,
+ final DataChunk decodedURI, int semicolonPos,
+ final MappingData mappingData) throws Exception {
+
+ mapperLock.readLock().lock();
+
+ try {
+ final CharChunk charChunk = decodedURI.getCharChunk();
+ final int oldStart = charChunk.getStart();
+ final int oldEnd = charChunk.getEnd();
+
+ if (semicolonPos == 0) {
+ semicolonPos = decodedURI.indexOf(';', 0);
+ }
+
+ DataChunk localDecodedURI = decodedURI;
+ if (semicolonPos >= 0) {
+ charChunk.setEnd(semicolonPos);
+ // duplicate the URI path, because Mapper may corrupt the attributes,
+ // which follow the path
+ localDecodedURI = req.getNote(DATA_CHUNK);
+ if (localDecodedURI == null) {
+ localDecodedURI = DataChunk.newInstance();
+ req.setNote(DATA_CHUNK, localDecodedURI);
+ }
+ localDecodedURI.duplicate(decodedURI);
+ }
+
+
+ try {
+ return map(req, localDecodedURI, mappingData);
+ } finally {
+ charChunk.setStart(oldStart);
+ charChunk.setEnd(oldEnd);
+ }
+ } finally {
+ mapperLock.readLock().unlock();
+ }
+ }
+
+ HttpHandler map(final Request req, final DataChunk decodedURI,
+ MappingData mappingData) throws Exception {
+
+ if (mappingData == null) {
+ mappingData = req.getNote(MAPPING_DATA);
+ }
+ // Map the request to its Adapter/Container and also it's Servlet if
+ // the request is targetted to the CoyoteAdapter.
+ mapper.map(req.getRequest().serverName(), decodedURI, mappingData);
+
+ updatePaths(req, mappingData);
+
+ ContextRootInfo contextRootInfo;
+ if (mappingData.context != null && (mappingData.context instanceof ContextRootInfo
+ || mappingData.wrapper instanceof ContextRootInfo)) {
+ if (mappingData.wrapper != null) {
+ contextRootInfo = (ContextRootInfo) mappingData.wrapper;
+ } else {
+ contextRootInfo = (ContextRootInfo) mappingData.context;
+ }
+ return contextRootInfo.getHttpHandler();
+ } else if (mappingData.context != null &&
+ "com.sun.enterprise.web.WebModule".equals(mappingData.context.getClass().getName())) {
+ return mapper.getHttpHandler();
+ }
+ return null;
+ }
+
+ public void register(String contextRoot, Collection<String> vs, HttpHandler httpService,
+ ApplicationContainer container) {
+
+ if (LOGGER.isLoggable(Level.FINE)) {
+ LOGGER.log(Level.FINE, "MAPPER({0}) REGISTER contextRoot: {1} adapter: {2} container: {3} port: {4}",
+ new Object[]{this, contextRoot, httpService, container, String.valueOf(listener.getPort())});
+ }
+
+ mapMultipleAdapter = true;
+ ContextRootInfo c = new ContextRootInfo(httpService, container);
+ for (String host : vs) {
+ mapper.addContext(host, contextRoot, c, new String[0], null);
+ /*
+ if (adapter instanceof StaticResourcesAdapter) {
+ mapper.addWrapper(host, ctx, wrapper, c);
+ }
+ */
+ }
+ }
+
+ public void unregister(String contextRoot) {
+ if (LOGGER.isLoggable(Level.FINE)) {
+ LOGGER.log(Level.FINE, "MAPPER ({0}) UNREGISTER contextRoot: {1}",
+ new Object[]{this, contextRoot});
+ }
+ for (String host : grizzlyService.hosts) {
+ mapper.removeContext(host, contextRoot);
+ }
+ }
+
+ public void register(final Endpoint endpoint) {
+ if (LOGGER.isLoggable(Level.FINE)) {
+ LOGGER.log(Level.FINE, "MAPPER({0}) REGISTER endpoint: {1}", endpoint);
+ }
+
+ mapMultipleAdapter = true;
+ final String contextRoot = endpoint.getContextRoot();
+ final Collection<String> vs = endpoint.getVirtualServers();
+
+ ContextRootInfo c = new ContextRootInfo(new ContextRootInfo.Holder() {
+ @Override
+ public HttpHandler getHttpHandler() {
+ return endpoint.getEndpointHandler();
+ }
+
+ @Override
+ public Object getContainer() {
+ return endpoint.getContainer();
+ }
+ });
+
+ for (String host : vs) {
+ mapper.addContext(host, contextRoot, c, new String[0], null);
+ /*
+ if (adapter instanceof StaticResourcesAdapter) {
+ mapper.addWrapper(host, ctx, wrapper, c);
+ }
+ */
+ }
+ }
+
+ public void unregister(final Endpoint endpoint) {
+ unregister(endpoint.getContextRoot());
+ }
+
+ private final static class HttpHandlerCallable implements Callable {
+ private final HttpHandler httpHandler;
+ private final Request request;
+ private final Response response;
+
+ public HttpHandlerCallable(final HttpHandler httpHandler,
+ final Request request, final Response response) {
+ this.httpHandler = httpHandler;
+ this.request = request;
+ this.response = response;
+ }
+
+ @Override
+ public Object call() throws Exception {
+ httpHandler.service(request, response);
+ return null;
+ }
+ }
+
+ private final class SuperCallable implements Callable {
+ final Request req;
+ final Response res;
+
+ public SuperCallable(Request req, Response res) {
+ this.req = req;
+ this.res = res;
+ }
+
+ @Override
+ public Object call() throws Exception {
+ ContainerMapper.super.service(req, res);
+ return null;
+ }
+ }
+
+ private static final class AfterServiceListenerImpl implements AfterServiceListener {
+
+ @Override
+ public void onAfterService(final Request request) {
+ final MappingData mappingData = request.getNote(MAPPING_DATA);
+ if (mappingData != null) {
+ mappingData.recycle();
+ }
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/DummyNetworkListener.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/DummyNetworkListener.java
new file mode 100644
index 0000000..f582f7b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/DummyNetworkListener.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.grizzly.config.dom.NetworkListeners;
+import org.glassfish.grizzly.config.dom.Protocol;
+import org.glassfish.grizzly.config.dom.ThreadPool;
+import org.glassfish.grizzly.config.dom.Transport;
+import java.util.ArrayList;
+import java.util.List;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.TransactionFailure;
+import org.jvnet.hk2.config.types.Property;
+
+/**
+ * This is a dummy implementation of the NetworkListener interface. This is used to create a fake
+ * network-listener elements. This is used only to support lazyInit attribute of iiop and jms services through the
+ * light weight listener. Ultimately, these services will move to their own network-listener
+ * element in domain.xml (at which point we have to get rid of this fake object). But till the time IIOP and JMS
+ * service elements in domain.xml can move to use network-listener element, we will create this "fake network-listener"
+ * which in turn will help start light weight listener for these services.
+ */
+public class DummyNetworkListener implements NetworkListener {
+ private String address = "0.0.0.0";
+ private String enabled = "true";
+ private String type = "standard";
+ private String name;
+ private String port;
+ private String protocol;
+ private String pool;
+ private String transport;
+ private String jkEnabled;
+ private String jkConfigurationFile;
+ private final List<Property> properties = new ArrayList<Property>();
+
+ public DummyNetworkListener() {
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public String getAddress() {
+ return address;
+ }
+
+ @Override
+ public void setAddress(String value) {
+ address = value;
+ }
+
+ @Override
+ public String getEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public void setEnabled(String enabled) {
+ this.enabled = enabled;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void setName(String value) {
+ name = value;
+ }
+
+ @Override
+ public String getPort() {
+ return port;
+ }
+
+ @Override
+ public void setPort(String value) {
+ port = value;
+ }
+
+ @Override
+ public String getProtocol() {
+ return protocol;
+ }
+
+ @Override
+ public void setProtocol(String value) {
+ protocol = value;
+ }
+
+ @Override
+ public String getThreadPool() {
+ return pool;
+ }
+
+ @Override
+ public void setThreadPool(String value) {
+ pool = value;
+ }
+
+ @Override
+ public String getTransport() {
+ return transport;
+ }
+
+ @Override
+ public void setTransport(String value) {
+ transport = value;
+ }
+
+ @Override
+ public String getJkEnabled() {
+ return jkEnabled;
+ }
+
+ @Override
+ public void setJkEnabled(String value) {
+ jkEnabled = value;
+ }
+
+ @Override
+ public String getJkConfigurationFile() {
+ return jkConfigurationFile;
+ }
+
+ @Override
+ public void setJkConfigurationFile(String jkConfigurationFile) {
+ this.jkConfigurationFile = jkConfigurationFile;
+ }
+
+ public void injectedInto(Object target){}
+
+ @Override
+ public <T extends ConfigBeanProxy> T createChild(Class<T> type) throws TransactionFailure {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Protocol findProtocol() {
+ return null;
+ }
+
+ @Override
+ public String findHttpProtocolName() {
+ return null;
+ }
+
+ @Override
+ public Protocol findHttpProtocol() {
+ return null;
+ }
+
+ @Override
+ public ThreadPool findThreadPool() {
+ return null;
+ }
+
+ @Override
+ public Transport findTransport() {
+ return null;
+ }
+
+ @Override
+ public NetworkListeners getParent() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends ConfigBeanProxy> T getParent(Class<T> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ConfigBeanProxy deepCopy(ConfigBeanProxy parent) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<Property> getProperty() {
+ return properties;
+ }
+
+ @Override
+ public Property getProperty(String name) {
+ if (name == null) return null;
+
+ for(Property property : properties) {
+ if (name.equals(property.getName())) {
+ return property;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getPropertyValue(String name) {
+ return getPropertyValue(name, null);
+ }
+
+ @Override
+ public String getPropertyValue(String name, String defaultValue) {
+ final Property property = getProperty(name);
+ if (property != null) {
+ return property.getValue();
+ }
+
+ return defaultValue;
+ }
+
+ @Override
+ public Property addProperty(Property prprt) {
+ if (properties.add(prprt)) {
+ return prprt;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Property lookupProperty(String string) {
+ return getProperty(name);
+ }
+
+ @Override
+ public Property removeProperty(String string) {
+ final Property prop = getProperty(name);
+ if(prop == null){
+ return null;
+ }
+ return removeProperty(prop);
+ }
+
+ @Override
+ public Property removeProperty(Property prprt) {
+ if (properties.remove(prprt)) {
+ return prprt;
+ }
+ return null;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/DynamicConfigListener.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/DynamicConfigListener.java
new file mode 100644
index 0000000..6173add
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/DynamicConfigListener.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import java.beans.PropertyChangeEvent;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.grizzly.config.dom.Http;
+import org.glassfish.grizzly.config.dom.Protocol;
+import org.glassfish.grizzly.config.dom.Ssl;
+import org.glassfish.grizzly.config.dom.ThreadPool;
+import org.glassfish.grizzly.config.dom.Transport;
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.SystemProperty;
+
+import org.jvnet.hk2.config.Changed;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.ConfigListener;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.NotProcessed;
+import org.jvnet.hk2.config.UnprocessedChangeEvents;
+
+import com.sun.enterprise.config.serverbeans.VirtualServer;
+import com.sun.enterprise.util.Result;
+import org.glassfish.grizzly.config.dom.FileCache;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantLock;
+import org.glassfish.grizzly.config.GrizzlyListener;
+import org.glassfish.grizzly.config.dom.NetworkConfig;
+import org.glassfish.grizzly.impl.FutureImpl;
+import org.glassfish.grizzly.impl.SafeFutureImpl;
+
+/**
+ * Grizzly dynamic configuration handler
+ *
+ * @author Alexey Stashok
+ */
+public class DynamicConfigListener implements ConfigListener {
+ private static final String ADMIN_LISTENER = "admin-listener";
+ private GrizzlyService grizzlyService;
+ private Config config;
+ private final Logger logger;
+ private static final int RECONFIG_LOCK_TIMEOUT_SEC = 30;
+ private static final ReentrantLock reconfigLock = new ReentrantLock();
+ private static final Map<Integer, FutureImpl> reconfigByPortLock =
+ new HashMap<Integer, FutureImpl>();
+
+ public DynamicConfigListener(final Config parent, final Logger logger) {
+ config = parent;
+ this.logger = logger;
+ }
+
+ @Override
+ public synchronized UnprocessedChangeEvents changed(final PropertyChangeEvent[] events) {
+ return ConfigSupport.sortAndDispatch(
+ events, new Changed() {
+ @Override
+ public <T extends ConfigBeanProxy> NotProcessed changed(TYPE type,
+ Class<T> tClass, T t) {
+ if (logger.isLoggable(Level.FINE)) {
+ logger.log(Level.FINE, "NetworkConfig changed {0} {1} {2}",
+ new Object[]{type, tClass, t});
+ }
+ if (tClass == NetworkListener.class && t instanceof NetworkListener) {
+ return processNetworkListener(type, (NetworkListener) t, events);
+ } else if (tClass == Http.class && t instanceof Http) {
+ return processProtocol(type, (Protocol) t.getParent(), events);
+ } else if (tClass == FileCache.class && t instanceof FileCache) {
+ return processProtocol(type, (Protocol) t.getParent().getParent(), null);
+ } else if (tClass == Ssl.class && t instanceof Ssl) {
+ /*
+ * Make sure the SSL parent is in fact a protocol. It could
+ * be a jmx-connector.
+ */
+ final ConfigBeanProxy parent = t.getParent();
+ if (parent instanceof Protocol) {
+ return processProtocol(type, (Protocol) parent, null);
+ }
+ } else if (tClass == Protocol.class && t instanceof Protocol) {
+ return processProtocol(type, (Protocol) t, null);
+ } else if (tClass == ThreadPool.class && t instanceof ThreadPool) {
+ NotProcessed notProcessed = null;
+ for (NetworkListener listener : ((ThreadPool) t).findNetworkListeners()) {
+ notProcessed = processNetworkListener(type, listener, null);
+ }
+ return notProcessed;
+ } else if (tClass == Transport.class && t instanceof Transport) {
+ NotProcessed notProcessed = null;
+ for (NetworkListener listener : ((Transport) t).findNetworkListeners()) {
+ notProcessed = processNetworkListener(type, listener, null);
+ }
+ return notProcessed;
+ } else if (tClass == VirtualServer.class
+ && t instanceof VirtualServer
+ && !grizzlyService.hasMapperUpdateListener()) {
+ return processVirtualServer(type, (VirtualServer) t);
+ } else if (tClass == SystemProperty.class && t instanceof SystemProperty) {
+ NetworkConfig networkConfig = config.getNetworkConfig();
+ if ((networkConfig != null) && ((SystemProperty)t).getName().endsWith("LISTENER_PORT")) {
+ for (NetworkListener listener : networkConfig.getNetworkListeners().getNetworkListener()) {
+ if (listener.getPort().equals(((SystemProperty)t).getValue())) {
+ return processNetworkListener(Changed.TYPE.CHANGE, listener, events);
+ }
+ }
+ }
+ return null;
+ }
+ return null;
+ }
+ }, logger);
+ }
+
+ private <T extends ConfigBeanProxy> NotProcessed processNetworkListener(Changed.TYPE type,
+ NetworkListener listener, PropertyChangeEvent[] changedProperties) {
+
+ if (findConfigName(listener).equals(findConfigName(config))) {
+
+ boolean isAdminListener = ADMIN_LISTENER.equals(listener.getName());
+ Lock portLock = null;
+ try {
+ portLock = acquirePortLock(listener);
+ if (type == Changed.TYPE.ADD) {
+ final int[] ports = portLock.getPorts();
+ if (isAdminListener && ports[ports.length - 1] == -1) {
+ return null;
+ }
+
+ final Future future = grizzlyService.createNetworkProxy(listener);
+ if (future != null) {
+ future.get(RECONFIG_LOCK_TIMEOUT_SEC, TimeUnit.SECONDS);
+ grizzlyService.registerContainerAdapters();
+ } else {
+ logger.log(Level.FINE, "Skipping proxy registration for the listener {0}",
+ listener.getName());
+ }
+ } else if (type == Changed.TYPE.REMOVE) {
+ if (!isAdminListener) {
+ grizzlyService.removeNetworkProxy(listener);
+ }
+ } else if (type == Changed.TYPE.CHANGE) {
+ if (isAdminListener) {
+ final boolean dynamic = isAdminDynamic(changedProperties);
+ if (dynamic) {
+ GrizzlyProxy proxy = (GrizzlyProxy) grizzlyService.lookupNetworkProxy(listener);
+ if (proxy != null) {
+ GrizzlyListener netListener = proxy.getUnderlyingListener();
+ netListener.processDynamicConfigurationChange(
+ grizzlyService.getHabitat(), changedProperties);
+ return null;
+ }
+ }
+ return null;
+ }
+
+ // Restart the network listener
+ grizzlyService.restartNetworkListener(listener, RECONFIG_LOCK_TIMEOUT_SEC, TimeUnit.SECONDS);
+ }
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "Network listener configuration error. Type: " + type, e);
+ } finally {
+ if (portLock != null) {
+ releaseListenerLock(portLock);
+ }
+ }
+ }
+ return null;
+ }
+
+ private String findConfigName(final ConfigBeanProxy child) {
+ ConfigBeanProxy bean = child;
+ while(bean != null && ! (bean instanceof Config)) {
+ bean = bean.getParent();
+ }
+ return bean != null ? ((Config) bean).getName() : "";
+ }
+
+ private boolean isAdminDynamic(PropertyChangeEvent[] events) {
+ if (events == null || events.length == 0) {
+ return false;
+ }
+ // for now, anything other than comet support will require a restart
+ for (PropertyChangeEvent e : events) {
+ if ("comet-support-enabled".equals(e.getPropertyName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private NotProcessed processProtocol(Changed.TYPE type, Protocol protocol, PropertyChangeEvent[] events) {
+ NotProcessed notProcessed = null;
+ for (NetworkListener listener : protocol.findNetworkListeners()) {
+ notProcessed = processNetworkListener(type, listener, events);
+ }
+ return notProcessed;
+ }
+
+ private NotProcessed processVirtualServer(Changed.TYPE type, VirtualServer vs) {
+ NotProcessed notProcessed = null;
+ for (NetworkListener n : vs.findNetworkListeners()) {
+ notProcessed = processNetworkListener(type, n, null);
+ }
+ return notProcessed;
+ }
+
+ public void setGrizzlyService(GrizzlyService grizzlyService) {
+ this.grizzlyService = grizzlyService;
+ }
+
+ public Logger getLogger() {
+ return logger;
+ }
+
+ /**
+ * Lock TCP ports, which will take part in the reconfiguration to avoid collisions
+ */
+ private Lock acquirePortLock(NetworkListener listener) throws InterruptedException, TimeoutException {
+ final boolean isLoggingFinest = logger.isLoggable(Level.FINEST);
+ final int port = getPort(listener);
+ try {
+ while (true) {
+ logger.finest("Aquire reconfig lock");
+ if (reconfigLock.tryLock(RECONFIG_LOCK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ Future lock = reconfigByPortLock.get(port);
+ if (isLoggingFinest) {
+ logger.log(Level.FINEST, "Reconfig lock for port: {0} is {1}",
+ new Object[]{port, lock});
+ }
+ int proxyPort = -1;
+ if (lock == null) {
+ final NetworkProxy runningProxy = grizzlyService.lookupNetworkProxy(listener);
+ if (runningProxy != null) {
+ proxyPort = runningProxy.getPort();
+ if (port != proxyPort) {
+ lock = reconfigByPortLock.get(proxyPort);
+ if (isLoggingFinest) {
+ logger.log(Level.FINEST, "Reconfig lock for proxyport: {0} is {1}",
+ new Object[]{proxyPort, lock});
+ }
+ } else {
+ proxyPort = -1;
+ }
+ }
+ }
+ if (lock != null) {
+ reconfigLock.unlock();
+ try {
+ logger.finest("Waiting on reconfig lock");
+ lock.get(RECONFIG_LOCK_TIMEOUT_SEC, TimeUnit.SECONDS);
+ } catch (ExecutionException e) {
+ throw new IllegalStateException(e);
+ }
+ } else {
+ final FutureImpl future = SafeFutureImpl.create();
+ if (isLoggingFinest) {
+ logger.log(Level.FINEST, "Set reconfig lock for ports: {0} and {1}: {2}",
+ new Object[]{port, proxyPort, future});
+ }
+ reconfigByPortLock.put(port, future);
+ if (proxyPort != -1) {
+ reconfigByPortLock.put(proxyPort, future);
+ }
+ return new Lock(port, proxyPort);
+ }
+ } else {
+ throw new TimeoutException("Lock timeout");
+ }
+ }
+ } finally {
+ if (reconfigLock.isHeldByCurrentThread()) {
+ reconfigLock.unlock();
+ }
+ }
+ }
+
+ private void releaseListenerLock(Lock lock) {
+ final boolean isLoggingFinest = logger.isLoggable(Level.FINEST);
+ reconfigLock.lock();
+ try {
+ final int[] ports = lock.getPorts();
+ if (isLoggingFinest) {
+ logger.log(Level.FINEST, "Release reconfig lock for ports: {0}",
+ Arrays.toString(ports));
+ }
+ FutureImpl future = null;
+ for (int port : ports) {
+ if (port != -1) {
+ future = reconfigByPortLock.remove(port);
+ }
+ }
+ if (future != null) {
+ if (isLoggingFinest) {
+ logger.log(Level.FINEST, "Release reconfig lock, set result: {0}",
+ future);
+ }
+ future.result(new Result<Thread>(Thread.currentThread()));
+ }
+ } finally {
+ reconfigLock.unlock();
+ }
+ }
+
+ private int getPort(NetworkListener listener) {
+ int listenerPort = -1;
+ try {
+ listenerPort = Integer.parseInt(listener.getPort());
+ } catch (NumberFormatException e) {
+ if (logger.isLoggable(Level.WARNING)) {
+ logger.log(Level.WARNING, "Can not parse network-listener port number: {0}",
+ listener.getPort());
+ }
+ }
+ return listenerPort;
+ }
+
+ private static final class Lock {
+ private final int[] ports;
+
+ public Lock(int... ports) {
+ this.ports = ports;
+ }
+
+ public int[] getPorts() {
+ return ports;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/Endpoint.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/Endpoint.java
new file mode 100644
index 0000000..3abf0fe
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/Endpoint.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import java.net.InetAddress;
+import java.util.Collection;
+import org.glassfish.api.container.Adapter;
+import org.glassfish.api.deployment.ApplicationContainer;
+import org.glassfish.grizzly.http.server.HttpHandler;
+
+/**
+ * Abstraction represents an endpoint, which could be registered on {@link NetworkProxy}.
+ *
+ * @author Alexey Stashok
+ */
+public abstract class Endpoint {
+
+ /**
+ * Creates <tt>Endpoint</tt> based on the passed {@link Adapter} descriptor.
+ * @param {@link Adapter}
+ * @return {@link Endpoint}, which can be registered on {@link NetworkProxy}.
+ */
+ public static Endpoint createEndpoint(final Adapter adapter) {
+ return new AdapterEndpoint(adapter);
+ }
+
+ /**
+ * @return the {@link InetAddress} on which this endpoint is listening
+ */
+ public abstract InetAddress getAddress();
+
+ /**
+ * Returns the listener port for this endpoint
+ * @return listener port
+ */
+ public abstract int getPort();
+
+ /**
+ * Returns the context root for this endpoint
+ * @return context root
+ */
+ public abstract String getContextRoot();
+
+ /**
+ * Get the underlying Grizzly {@link HttpHandler}.
+ *
+ * @return the underlying Grizzly {@link HttpHandler}.
+ */
+ public abstract HttpHandler getEndpointHandler();
+
+ /**
+ * Returns the virtual servers supported by this endpoint
+ * @return List<String> the virtual server list supported by the endpoint
+ */
+ public abstract Collection<String> getVirtualServers();
+
+ /**
+ * Return the {@link ApplicationContainer} endpoint belongs to.
+ * @return the {@link ApplicationContainer} endpoint belongs to.
+ */
+ public abstract ApplicationContainer getContainer();
+
+
+ /**
+ * {@link Adapter} based <tt>Endpoint</tt> implementation.
+ */
+ private static class AdapterEndpoint extends Endpoint {
+ private final Adapter adapter;
+
+ public AdapterEndpoint(final Adapter adapter) {
+ this.adapter = adapter;
+ }
+
+ @Override
+ public InetAddress getAddress() {
+ return adapter.getListenAddress();
+ }
+
+ @Override
+ public int getPort() {
+ return adapter.getListenPort();
+ }
+
+ @Override
+ public String getContextRoot() {
+ return adapter.getContextRoot();
+ }
+
+ @Override
+ public HttpHandler getEndpointHandler() {
+ return adapter.getHttpService();
+ }
+
+ @Override
+ public Collection<String> getVirtualServers() {
+ return adapter.getVirtualServers();
+ }
+
+ @Override
+ public ApplicationContainer getContainer() {
+ return null;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/EndpointMapper.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/EndpointMapper.java
new file mode 100644
index 0000000..bf0afda
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/EndpointMapper.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import java.util.Collection;
+import org.glassfish.api.deployment.ApplicationContainer;
+import org.glassfish.api.container.EndpointRegistrationException;
+
+/**
+ * registration interface to use with the Mapper classes.
+ *
+ * @author Jeanfrancois Arcand
+ */
+public interface EndpointMapper<E> {
+
+
+ /**
+ * Registers a new endpoint (proxy implementation) for a particular
+ * context-root. All request coming with the context root will be dispatched
+ * to the proxy instance passed in.
+ * @param contextRoot for the proxy
+ * @param endpointAdapter servicing requests.
+ */
+ public void registerEndpoint(String contextRoot, Collection<String> vsServers, E adapter,
+ ApplicationContainer container) throws EndpointRegistrationException;
+
+
+ /**
+ * Removes the context-root from our list of endpoints.
+ */
+ public void unregisterEndpoint(String contextRoot, ApplicationContainer app) throws EndpointRegistrationException;
+
+ /**
+ * Registers a new endpoint (proxy implementation) defined by the passed
+ * {@link Endpoint} object.
+ * @param endpoint {@link Endpoint}
+ */
+ public void registerEndpoint(Endpoint endpoint) throws EndpointRegistrationException;
+
+ /**
+ * Removes the {@link Endpoint} from our list of endpoints.
+ * @param endpoint {@link Endpoint}
+ */
+ public void unregisterEndpoint(Endpoint endpoint) throws EndpointRegistrationException;
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishErrorPageGenerator.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishErrorPageGenerator.java
new file mode 100644
index 0000000..265cb68
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishErrorPageGenerator.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import com.sun.appserv.server.util.Version;
+import org.glassfish.grizzly.http.server.ErrorPageGenerator;
+import org.glassfish.grizzly.http.server.Request;
+
+/**
+ * Glassfish default {@link ErrorPageGenerator}.
+ */
+public class GlassfishErrorPageGenerator implements ErrorPageGenerator {
+
+ @Override
+ public String generate(final Request request, final int status,
+ final String reasonPhrase, final String description,
+ final Throwable exception) {
+
+
+ if (status == 404) {
+ return HttpUtils.getErrorPage(Version.getVersion(),
+ "The requested resource is not available.", "404");
+ } else {
+ return HttpUtils.getErrorPage(Version.getVersion(),
+ "The server encountered an internal error that prevented it from fulfilling this request.", "500");
+ }
+ }
+}
+
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishNetworkListener.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishNetworkListener.java
new file mode 100644
index 0000000..60724c9
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GlassfishNetworkListener.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import com.sun.appserv.server.util.Version;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.sun.enterprise.config.serverbeans.VirtualServer;
+import com.sun.enterprise.v3.services.impl.monitor.ConnectionMonitor;
+import com.sun.enterprise.v3.services.impl.monitor.FileCacheMonitor;
+import com.sun.enterprise.v3.services.impl.monitor.GrizzlyMonitoring;
+import com.sun.enterprise.v3.services.impl.monitor.KeepAliveMonitor;
+import com.sun.enterprise.v3.services.impl.monitor.ThreadPoolMonitor;
+import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.config.GenericGrizzlyListener;
+import org.glassfish.grizzly.config.dom.Http;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.grizzly.config.dom.Protocol;
+import org.glassfish.grizzly.config.dom.ThreadPool;
+import org.glassfish.grizzly.config.dom.Transport;
+import org.glassfish.grizzly.filterchain.FilterChainBuilder;
+import org.glassfish.grizzly.filterchain.FilterChainContext;
+import org.glassfish.grizzly.http.HttpHeader;
+import org.glassfish.grizzly.http.HttpRequestPacket;
+import org.glassfish.grizzly.http.HttpResponsePacket;
+import org.glassfish.grizzly.http.KeepAlive;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.ServerFilterConfiguration;
+import org.glassfish.grizzly.http.server.filecache.FileCache;
+import org.glassfish.grizzly.http.server.util.Mapper;
+import org.glassfish.grizzly.http.util.Header;
+import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
+import org.glassfish.grizzly.utils.DelayedExecutor;
+import org.glassfish.hk2.api.DynamicConfiguration;
+import org.glassfish.hk2.api.DynamicConfigurationService;
+import org.glassfish.hk2.api.IndexedFilter;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.utilities.AbstractActiveDescriptor;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
+import org.glassfish.internal.grizzly.V3Mapper;
+import org.jvnet.hk2.config.types.Property;
+
+public class GlassfishNetworkListener extends GenericGrizzlyListener {
+ private final GrizzlyService grizzlyService;
+ private final NetworkListener networkListener;
+ private final Logger logger;
+
+ private volatile HttpAdapter httpAdapter;
+
+ public GlassfishNetworkListener(final GrizzlyService grizzlyService,
+ final NetworkListener networkListener,
+ final Logger logger) {
+ this.grizzlyService = grizzlyService;
+ this.networkListener = networkListener;
+ this.logger = logger;
+ }
+
+ public NetworkListener getNetworkListener() {
+ return networkListener;
+ }
+
+ @Override
+ public void start() throws IOException {
+ super.start();
+ }
+
+ @Override
+ public void stop() throws IOException {
+ ServiceLocator locator = grizzlyService.getHabitat();
+ IndexedFilter removeFilter = BuilderHelper.createNameAndContractFilter(Mapper.class.getName(),
+ (address.toString() + port));
+
+ DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
+ DynamicConfiguration config = dcs.createDynamicConfiguration();
+
+ config.addUnbindFilter(removeFilter);
+
+ config.commit();
+
+ unregisterMonitoringStatsProviders();
+ super.stop();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T getAdapter(Class<T> adapterClass) {
+ if (HttpAdapter.class.equals(adapterClass)) {
+ return (T) httpAdapter;
+ }
+
+ return super.getAdapter(adapterClass);
+ }
+
+ @Override
+ protected void configureTransport(final NetworkListener networkListener,
+ final Transport transportConfig,
+ final FilterChainBuilder filterChainBuilder) {
+
+ super.configureTransport(networkListener, transportConfig,
+ filterChainBuilder);
+
+ transport.getConnectionMonitoringConfig().addProbes(new ConnectionMonitor(
+ grizzlyService.getMonitoring(), name, transport));
+ }
+
+ @Override
+ protected void configureHttpProtocol(final ServiceLocator habitat,
+ final NetworkListener networkListener,
+ final Http http, final FilterChainBuilder filterChainBuilder,
+ boolean securityEnabled) {
+
+ if (httpAdapter == null) {
+ registerMonitoringStatsProviders();
+
+ final V3Mapper mapper = new V3Mapper(logger);
+
+ mapper.setPort(port);
+ mapper.setId(name);
+
+ final ContainerMapper containerMapper = new ContainerMapper(grizzlyService, this);
+ containerMapper.setMapper(mapper);
+ containerMapper.setDefaultHost(http.getDefaultVirtualServer());
+ containerMapper.setRequestURIEncoding(http.getUriEncoding());
+ containerMapper.configureMapper();
+
+ VirtualServer vs = null;
+ String webAppRootPath = null;
+
+ final Collection<VirtualServer> list = grizzlyService.getHabitat().getAllServices(VirtualServer.class);
+ final String vsName = http.getDefaultVirtualServer();
+ for (final VirtualServer virtualServer : list) {
+ if (virtualServer.getId().equals(vsName)) {
+ vs = virtualServer;
+ webAppRootPath = vs.getDocroot();
+
+ if (!grizzlyService.hasMapperUpdateListener() && vs.getProperty() != null
+ && !vs.getProperty().isEmpty()) {
+ for (final Property p : vs.getProperty()) {
+ final String propertyName = p.getName();
+ if (propertyName.startsWith("alternatedocroot")) {
+ String value = p.getValue();
+ String[] mapping = value.split(" ");
+
+ if (mapping.length != 2) {
+ logger.log(Level.WARNING, "Invalid alternate_docroot {0}", value);
+ continue;
+ }
+
+ String docBase = mapping[1].substring("dir=".length());
+ String urlPattern = mapping[0].substring("from=".length());
+ containerMapper.addAlternateDocBase(urlPattern, docBase);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ httpAdapter = new HttpAdapterImpl(vs, containerMapper, webAppRootPath);
+ containerMapper.addDocRoot(webAppRootPath);
+
+ AbstractActiveDescriptor<V3Mapper> aad = BuilderHelper.createConstantDescriptor(mapper);
+ aad.addContractType(Mapper.class);
+ aad.setName(address.toString() + port);
+
+ ServiceLocatorUtilities.addOneDescriptor(grizzlyService.getHabitat(), aad);
+ super.configureHttpProtocol(habitat, networkListener, http, filterChainBuilder, securityEnabled);
+ final Protocol protocol = http.getParent();
+ for (NetworkListener listener : protocol.findNetworkListeners()) {
+ grizzlyService.notifyMapperUpdateListeners(listener, mapper);
+ }
+ } else {
+ super.configureHttpProtocol(habitat, networkListener, http, filterChainBuilder, securityEnabled);
+ }
+ }
+
+ @Override
+ protected ServerFilterConfiguration getHttpServerFilterConfiguration(Http http) {
+ // Set the default Glassfish error page generator
+ final ServerFilterConfiguration config =
+ super.getHttpServerFilterConfiguration(http);
+ config.setDefaultErrorPageGenerator(new GlassfishErrorPageGenerator());
+ return config;
+ }
+
+ @Override
+ protected HttpHandler getHttpHandler() {
+ return httpAdapter.getMapper();
+ }
+
+ @Override
+ protected KeepAlive configureKeepAlive(Http http) {
+ final KeepAlive keepAlive = super.configureKeepAlive(http);
+ keepAlive.getMonitoringConfig().addProbes(new KeepAliveMonitor(
+ grizzlyService.getMonitoring(), name, keepAlive));
+ return keepAlive;
+ }
+
+ @Override
+ protected FileCache configureHttpFileCache(org.glassfish.grizzly.config.dom.FileCache cache) {
+
+ final FileCache fileCache = super.configureHttpFileCache(cache);
+ fileCache.getMonitoringConfig().addProbes(new FileCacheMonitor(
+ grizzlyService.getMonitoring(), name, fileCache));
+
+ return fileCache;
+ }
+
+ @Override
+ protected ThreadPoolConfig configureThreadPoolConfig(final NetworkListener networkListener,
+ final ThreadPool threadPool) {
+
+ final ThreadPoolConfig config = super.configureThreadPoolConfig(
+ networkListener, threadPool);
+ config.getInitialMonitoringConfig().addProbes(new ThreadPoolMonitor(
+ grizzlyService.getMonitoring(), name, config));
+ return config;
+ }
+
+ @Override
+ protected org.glassfish.grizzly.http.HttpServerFilter createHttpServerCodecFilter(
+ final Http http,
+ final boolean isChunkedEnabled, final int headerBufferLengthBytes,
+ final String defaultResponseType, final KeepAlive keepAlive,
+ final DelayedExecutor delayedExecutor,
+ final int maxRequestHeaders, final int maxResponseHeaders) {
+
+ final org.glassfish.grizzly.http.HttpServerFilter httpCodecFilter =
+ new GlassfishHttpCodecFilter(
+ http == null || Boolean.parseBoolean(http.getXpoweredBy()),
+ isChunkedEnabled,
+ headerBufferLengthBytes,
+ defaultResponseType,
+ keepAlive,
+ delayedExecutor,
+ maxRequestHeaders,
+ maxResponseHeaders);
+
+ if (http != null) { // could be null for HTTP redirect
+ httpCodecFilter.setMaxPayloadRemainderToSkip(
+ Integer.parseInt(http.getMaxSwallowingInputBytes()));
+
+ httpCodecFilter.setAllowPayloadForUndefinedHttpMethods(
+ Boolean.parseBoolean(http.getAllowPayloadForUndefinedHttpMethods()));
+ }
+
+ return httpCodecFilter;
+ }
+
+
+ protected void registerMonitoringStatsProviders() {
+ final String nameLocal = name;
+ final GrizzlyMonitoring monitoring = grizzlyService.getMonitoring();
+
+ monitoring.registerThreadPoolStatsProvider(nameLocal);
+ monitoring.registerKeepAliveStatsProvider(nameLocal);
+ monitoring.registerFileCacheStatsProvider(nameLocal);
+ monitoring.registerConnectionQueueStatsProvider(nameLocal);
+ }
+
+ protected void unregisterMonitoringStatsProviders() {
+ final String localName = name;
+ final GrizzlyMonitoring monitoring = grizzlyService.getMonitoring();
+
+ monitoring.unregisterThreadPoolStatsProvider(localName);
+ monitoring.unregisterKeepAliveStatsProvider(localName);
+ monitoring.unregisterFileCacheStatsProvider(localName);
+ monitoring.unregisterConnectionQueueStatsProvider(localName);
+ }
+
+ static List<String> toArray(String s, String token) {
+ final ArrayList<String> list = new ArrayList<String>();
+
+ int from = 0;
+ do {
+ final int idx = s.indexOf(token, from);
+
+ if (idx == -1) {
+ final String str = s.substring(from, s.length()).trim();
+ list.add(str);
+ break;
+ }
+
+ final String str = s.substring(from, idx).trim();
+ list.add(str);
+
+ from = idx + 1;
+
+ } while (true);
+
+ return list;
+ }
+
+ protected static class HttpAdapterImpl implements HttpAdapter {
+ private final VirtualServer virtualServer;
+ private final ContainerMapper conainerMapper;
+ private final String webAppRootPath;
+
+ public HttpAdapterImpl(VirtualServer virtualServer, ContainerMapper conainerMapper, String webAppRootPath) {
+ this.virtualServer = virtualServer;
+ this.conainerMapper = conainerMapper;
+ this.webAppRootPath = webAppRootPath;
+ }
+
+
+ @Override
+ public ContainerMapper getMapper() {
+ return conainerMapper;
+ }
+
+ @Override
+ public VirtualServer getVirtualServer() {
+ return virtualServer;
+ }
+
+ @Override
+ public String getWebAppRootPath() {
+ return webAppRootPath;
+ }
+ }
+
+ /**
+ * Glassfish specific HttpCodecFilter extension.
+ */
+ private static class GlassfishHttpCodecFilter extends org.glassfish.grizzly.http.HttpServerFilter {
+ private final String serverVersion;
+ private final String xPoweredBy;
+
+ public GlassfishHttpCodecFilter(
+ final boolean isXPoweredByEnabled,
+ final boolean chunkingEnabled,
+ final int maxHeadersSize,
+ final String defaultResponseContentType,
+ final KeepAlive keepAlive, final DelayedExecutor executor,
+ final int maxRequestHeaders, final int maxResponseHeaders) {
+ super(chunkingEnabled, maxHeadersSize, defaultResponseContentType,
+ keepAlive, executor, maxRequestHeaders, maxResponseHeaders);
+
+ /*
+ * Set the server info.
+ * By default, the server info is taken from Version#getVersion.
+ * However, customers may override it via the product.name system
+ * property.
+ * Some customers prefer not to disclose the server info
+ * for security reasons, in which case they would set the value of the
+ * product.name system property to the empty string. In this case,
+ * the server name will not be publicly disclosed via the "Server"
+ * HTTP response header (which will be suppressed) or any container
+ * generated error pages. However, it will still appear in the
+ * server logs (see IT 6900).
+ *
+ * Taken from com.sun.enterprise.web.WebContainer code
+ */
+ String serverInfo = System.getProperty("product.name");
+
+ serverVersion = serverInfo != null ? serverInfo : Version.getVersion();
+
+ if (isXPoweredByEnabled) {
+ xPoweredBy = "Servlet/3.1 JSP/2.3 "
+ + "(" + ((serverInfo != null && !serverInfo.isEmpty()) ? serverInfo : Version.getVersion())
+ + " Java/"
+ + System.getProperty("java.vm.vendor") + "/"
+ + System.getProperty("java.specification.version") + ")";
+ } else {
+ xPoweredBy = null;
+ }
+ }
+
+ @Override
+ protected boolean onHttpHeaderParsed(final HttpHeader httpHeader,
+ final Buffer buffer,
+ final FilterChainContext ctx) {
+
+ final boolean result = super.onHttpHeaderParsed(httpHeader,
+ buffer, ctx);
+
+ final HttpRequestPacket request = (HttpRequestPacket) httpHeader;
+ final HttpResponsePacket response = request.getResponse();
+
+ // Set response "Server" header
+ if (serverVersion != null && !serverVersion.isEmpty()) {
+ response.addHeader(Header.Server, serverVersion);
+ }
+
+ // Set response "X-Powered-By" header
+ if (xPoweredBy != null) {
+ response.addHeader(Header.XPoweredBy, xPoweredBy);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java
new file mode 100644
index 0000000..66c74af
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.api.container.EndpointRegistrationException;
+import org.glassfish.api.deployment.ApplicationContainer;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import com.sun.enterprise.util.Result;
+import java.util.concurrent.Callable;
+import org.glassfish.api.logging.LogHelper;
+import org.glassfish.grizzly.Grizzly;
+import org.glassfish.grizzly.config.GenericGrizzlyListener;
+import org.glassfish.grizzly.config.GrizzlyListener;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.impl.FutureImpl;
+import org.glassfish.grizzly.utils.Futures;
+import org.glassfish.kernel.KernelLoggerInfo;
+
+/**
+ * This class is responsible for configuring Grizzly.
+ *
+ * @author Jerome Dochez
+ * @author Jeanfrancois Arcand
+ */
+public class GrizzlyProxy implements NetworkProxy {
+ final Logger logger;
+ final NetworkListener networkListener;
+
+ protected GrizzlyListener grizzlyListener;
+ private int portNumber;
+
+ public final static String LEADER_FOLLOWER
+ = "org.glassfish.grizzly.useLeaderFollower";
+
+ public final static String AUTO_CONFIGURE
+ = "org.glassfish.grizzly.autoConfigure";
+
+ // <http-listener> 'address' attribute
+ private InetAddress address;
+
+ private GrizzlyService grizzlyService;
+
+ //private VirtualServer vs;
+
+
+ public GrizzlyProxy(GrizzlyService service, NetworkListener listener) {
+ grizzlyService = service;
+ logger = service.getLogger();
+ networkListener = listener;
+ }
+
+ /**
+ * Create a <code>GrizzlyServiceListener</code> based on a NetworkListener
+ * configuration object.
+ */
+ public void initialize() throws IOException {
+ String port = networkListener.getPort();
+ portNumber = 8080;
+ if (port == null) {
+ logger.severe(KernelLoggerInfo.noPort);
+ throw new RuntimeException("Cannot find port information from domain configuration");
+ }
+ try {
+ portNumber = Integer.parseInt(port);
+ } catch (NumberFormatException e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.badPort, port);
+ }
+ try {
+ address = InetAddress.getByName(networkListener.getAddress());
+ } catch (UnknownHostException ex) {
+ LogHelper.log(logger, Level.SEVERE, KernelLoggerInfo.badAddress, ex, address);
+ }
+
+ grizzlyListener = createGrizzlyListener(networkListener);
+
+ grizzlyListener.configure(grizzlyService.getHabitat(), networkListener);
+ }
+
+ protected GrizzlyListener createGrizzlyListener(
+ final NetworkListener networkListener) {
+ if (GrizzlyService.isLightWeightListener(networkListener)) {
+ return createServiceInitializerListener(networkListener);
+ } else {
+ return createGlassfishListener(networkListener);
+ }
+ }
+
+ protected GrizzlyListener createGlassfishListener(
+ final NetworkListener networkListener) {
+ return new GlassfishNetworkListener(grizzlyService,
+ networkListener, logger);
+ }
+
+ protected GrizzlyListener createServiceInitializerListener(
+ final NetworkListener networkListener) {
+ return new ServiceInitializerListener(grizzlyService,
+ networkListener, logger);
+ }
+
+ static ArrayList<String> toArray(String list, String token){
+ return new ArrayList<String>(Arrays.asList(list.split(token)));
+ }
+
+ /**
+ * Stops the Grizzly service.
+ */
+ @Override
+ public void stop() throws IOException {
+ grizzlyListener.stop();
+ }
+
+ @Override
+ public void destroy() {
+ grizzlyListener.destroy();
+ }
+
+ @Override
+ public String toString() {
+ return "GrizzlyProxy{" +
+ //"virtual server=" + vs +
+ "address=" + address +
+ ", portNumber=" + portNumber +
+ '}';
+ }
+
+
+ /*
+ * Registers a new endpoint (adapter implementation) for a particular
+ * context-root. All request coming with the context root will be dispatched
+ * to the adapter instance passed in.
+ * @param contextRoot for the adapter
+ * @param endpointAdapter servicing requests.
+ */
+ @Override
+ public void registerEndpoint(String contextRoot, Collection<String> vsServers,
+ HttpHandler endpointService,
+ ApplicationContainer container) throws EndpointRegistrationException {
+
+ // e.g., there is no admin service in an instance
+ if (contextRoot == null) {
+ return;
+ }
+
+ if (endpointService == null) {
+ throw new EndpointRegistrationException(
+ "The endpoint adapter is null");
+ }
+
+ final HttpAdapter httpAdapter = grizzlyListener.getAdapter(HttpAdapter.class);
+ if (httpAdapter != null) {
+ httpAdapter.getMapper().register(contextRoot, vsServers, endpointService, container);
+ }
+ }
+
+ /**
+ * Removes the context-root from our list of endpoints.
+ */
+ @Override
+ public void unregisterEndpoint(String contextRoot, ApplicationContainer app) throws EndpointRegistrationException {
+ final HttpAdapter httpAdapter = grizzlyListener.getAdapter(HttpAdapter.class);
+ if (httpAdapter != null) {
+ httpAdapter.getMapper().unregister(contextRoot);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void registerEndpoint(final Endpoint endpoint) {
+ final HttpAdapter httpAdapter = grizzlyListener.getAdapter(HttpAdapter.class);
+ if (httpAdapter != null) {
+ httpAdapter.getMapper().register(endpoint);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void unregisterEndpoint(final Endpoint endpoint) throws EndpointRegistrationException {
+ unregisterEndpoint(endpoint.getContextRoot(), endpoint.getContainer());
+ }
+
+
+ @Override
+ public Future<Result<Thread>> start() throws IOException {
+ final FutureImpl<Result<Thread>> future =
+ Futures.<Result<Thread>>createUnsafeFuture();
+
+ if (!isAjpEnabled(grizzlyListener)) {
+ // If this is not AJP listener - initiate startup right now
+ start0();
+ } else {
+ // For AJP listener we have to wait until server is up and ready
+ // to process incoming requests
+ // Related to the GLASSFISH-18267
+ grizzlyService.addServerReadyListener(new Callable<Void>() {
+
+ @Override
+ public Void call() throws Exception {
+ start0();
+ return null;
+ }
+ });
+ }
+
+ future.result(new Result<Thread>(Thread.currentThread()));
+ return future;
+ }
+
+ /**
+ * Start internal Grizzly listener.
+ * @throws IOException
+ */
+ protected void start0() throws IOException {
+ final long t1 = System.currentTimeMillis();
+
+ grizzlyListener.start();
+
+ if (logger.isLoggable(Level.INFO)) {
+ logger.log(Level.INFO, KernelLoggerInfo.grizzlyStarted,
+ new Object[]{Grizzly.getDotedVersion(),
+ System.currentTimeMillis() - t1,
+ grizzlyListener.getAddress() + ":" + grizzlyListener.getPort()});
+ }
+ }
+
+ @Override
+ public int getPort() {
+ return portNumber;
+ }
+
+ @Override
+ public InetAddress getAddress() {
+ return address;
+ }
+
+ public GrizzlyListener getUnderlyingListener() {
+ return grizzlyListener;
+ }
+
+ private static boolean isAjpEnabled(final GrizzlyListener grizzlyListener) {
+ return (grizzlyListener instanceof GenericGrizzlyListener) &&
+ ((GenericGrizzlyListener) grizzlyListener).isAjpEnabled();
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java
new file mode 100644
index 0000000..6dd80fd
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java
@@ -0,0 +1,852 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import com.sun.enterprise.config.serverbeans.HttpService;
+import com.sun.enterprise.config.serverbeans.SystemProperty;
+import com.sun.enterprise.config.serverbeans.VirtualServer;
+import com.sun.enterprise.util.Result;
+import com.sun.enterprise.util.StringUtils;
+import com.sun.enterprise.v3.services.impl.monitor.GrizzlyMonitoring;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.glassfish.api.FutureProvider;
+import org.glassfish.api.StartupRunLevel;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.container.EndpointRegistrationException;
+import org.glassfish.api.container.RequestDispatcher;
+import org.glassfish.api.deployment.ApplicationContainer;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.api.event.RestrictTo;
+import org.glassfish.common.util.Constants;
+import org.glassfish.grizzly.config.GenericGrizzlyListener;
+import org.glassfish.grizzly.config.dom.NetworkConfig;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.grizzly.config.dom.NetworkListeners;
+import org.glassfish.grizzly.config.dom.Protocol;
+import org.glassfish.grizzly.http.HttpCodecFilter;
+import org.glassfish.grizzly.http.HttpProbe;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.util.Mapper;
+import org.glassfish.grizzly.impl.FutureImpl;
+import org.glassfish.grizzly.utils.Futures;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.PreDestroy;
+import org.glassfish.hk2.api.Rank;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.ConfigBeanProxy;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.ObservableBean;
+import org.jvnet.hk2.config.Transactions;
+
+/**
+ * The Network Service is responsible for starting grizzly and register the
+ * top level proxy. It is also providing a runtime service where other
+ * services (like admin for instance) can register endpoints proxy to
+ * particular context root.
+ *
+ * @author Jerome Dochez
+ */
+@Service
+@RunLevel(StartupRunLevel.VAL)
+@Rank(Constants.IMPORTANT_RUN_LEVEL_SERVICE)
+public class GrizzlyService implements RequestDispatcher, PostConstruct, PreDestroy, EventListener, FutureProvider<Result<Thread>> {
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ @Inject
+ private ServiceLocator serviceLocator;
+
+ @Inject
+ Transactions transactions;
+
+ @Inject
+ Events events;
+
+ private static final Logger LOGGER = KernelLoggerInfo.getLogger();
+
+ private final Collection<NetworkProxy> proxies = new LinkedBlockingQueue<NetworkProxy>();
+
+ volatile List<Future<Result<Thread>>> futures;
+
+ Collection<String> hosts = new ArrayList<String>();
+
+ private final GrizzlyMonitoring monitoring;
+
+ private static final String NETWORK_CONFIG_PREFIX = "";
+
+ private final Set<MapperUpdateListener> mapperUpdateListeners =
+ Collections.newSetFromMap(
+ new ConcurrentHashMap<MapperUpdateListener, Boolean>());
+
+ /**
+ * HTTP Mapper update lock.
+ */
+ private final ReentrantReadWriteLock mapperLock =
+ new ReentrantReadWriteLock();
+
+ private DynamicConfigListener configListener;
+
+ // Future to be set on server READY_EVENT
+ private final FutureImpl<Boolean> serverReadyFuture =
+ Futures.<Boolean>createSafeFuture();
+ // Listeners to be notified once server is in READY state.
+ private final Queue<Callable<Void>> serverReadyListeners =
+ new ConcurrentLinkedQueue<Callable<Void>>();
+
+ public GrizzlyService() {
+ futures = new ArrayList<Future<Result<Thread>>>();
+ monitoring = new GrizzlyMonitoring();
+ }
+
+ /**
+ * Add the new proxy to our list of proxies.
+ * @param proxy new proxy to be added
+ */
+ public void addNetworkProxy(NetworkProxy proxy) {
+ proxies.add(proxy);
+ }
+
+
+ /**
+ * Remove the proxy from our list of proxies by listener.
+ * @param listener removes the proxy associated with the specified listener
+ * @return <tt>true</tt>, if proxy removed,
+ * <tt>false</tt> if no proxy was associated with the specified listener.
+ */
+ public boolean removeNetworkProxy(NetworkListener listener) {
+ return removeNetworkProxy(lookupNetworkProxy(listener));
+ }
+
+
+ /**
+ * Remove the proxy from our list of proxies by id.
+ * @return <tt>true</tt>, if proxy on specified port was removed,
+ * <tt>false</tt> if no proxy was associated with the port.
+ */
+ public boolean removeNetworkProxy(String id) {
+ NetworkProxy proxy = getNetworkProxy(id);
+ return removeNetworkProxy(proxy);
+ }
+
+ private NetworkProxy getNetworkProxy(String id) {
+ NetworkProxy proxy = null;
+ for (NetworkProxy p : proxies) {
+ if (p instanceof GrizzlyProxy) {
+ GrizzlyProxy grizzlyProxy = (GrizzlyProxy) p;
+ if (grizzlyProxy.networkListener != null &&
+ grizzlyProxy.networkListener.getName() != null &&
+ grizzlyProxy.networkListener.getName().equals(id)) {
+ proxy = p;
+ break;
+ }
+ }
+ }
+
+ return proxy;
+ }
+
+ /**
+ * Remove the proxy from our list of proxies.
+ * @return <tt>true</tt>, if proxy on specified port was removed,
+ * <tt>false</tt> otherwise.
+ */
+ public boolean removeNetworkProxy(NetworkProxy proxy) {
+ if (proxy != null) {
+ try {
+ proxy.stop();
+ } catch (IOException e) {
+ LOGGER.log(Level.WARNING, KernelLoggerInfo.grizzlyStopProxy, e);
+ }
+
+ proxy.destroy();
+ proxies.remove(proxy);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Lookup {@link GrizzlyProxy}, which corresponds to the {@link NetworkListener}.
+ *
+ * @param listener {@link NetworkListener}.
+ * @return {@link GrizzlyProxy}, or <tt>null</tt>, if correspondent {@link GrizzlyProxy} wasn't found.
+ */
+ public NetworkProxy lookupNetworkProxy(NetworkListener listener) {
+ int listenerPort = -1;
+ InetAddress address = null;
+ try {
+ listenerPort = Integer.parseInt(listener.getPort());
+ } catch (NumberFormatException e) {
+ LOGGER.log(Level.FINE, e.toString());
+ }
+
+ try {
+ address = InetAddress.getByName(listener.getAddress());
+ } catch (UnknownHostException uhe) {
+ LOGGER.log(Level.FINE, uhe.toString());
+ }
+
+ if (listenerPort != -1) {
+ for (NetworkProxy p : proxies) {
+ if (p.getPort() == listenerPort && p.getAddress().equals(address)) {
+ return p;
+ }
+ }
+ }
+
+ final String listenerId = listener.getName();
+
+ for (NetworkProxy p : proxies) {
+ if (p instanceof GrizzlyProxy) {
+ GrizzlyProxy grizzlyProxy = (GrizzlyProxy) p;
+ if (grizzlyProxy.networkListener != null &&
+ grizzlyProxy.networkListener.getName() != null &&
+ grizzlyProxy.networkListener.getName().equals(listenerId)) {
+ return p;
+ }
+ }
+ }
+
+ return null;
+
+ }
+
+ /**
+ * Restart {@link NetworkListener}.
+ *
+ * @param networkListenerName
+ * @param timeout restart timeout, if timeout value is negative - then no timeout will be applied.
+ * @param timeUnit restart timeout unit
+ *
+ * @throws TimeoutException thrown if timeout had expired before server succeeded to restart
+ * @throws IOException
+ */
+ public void restartNetworkListener(String networkListenerName,
+ long timeout, TimeUnit timeUnit) throws IOException, TimeoutException {
+ restartNetworkListener(
+ config.getNetworkConfig().getNetworkListener(networkListenerName),
+ timeout, timeUnit);
+ }
+
+ /**
+ * Restart {@link NetworkListener}.
+ *
+ * @param networkListener {@link NetworkListener}
+ * @param timeout restart timeout, if timeout value is negative - then no timeout will be applied.
+ * @param timeUnit restart timeout unit
+ *
+ * @throws TimeoutException thrown if timeout had expired before server succeeded to restart
+ * @throws IOException
+ */
+ public void restartNetworkListener(NetworkListener networkListener,
+ long timeout, TimeUnit timeUnit) throws IOException, TimeoutException {
+
+ // Restart GrizzlyProxy on the address/port
+ // Address/port/id could have been changed - so try to find
+ // corresponding proxy both ways
+ NetworkProxy proxy = lookupNetworkProxy(networkListener);
+ Map<Class<? extends HttpCodecFilter>, List<HttpProbe>> filterToProbeMapping = new HashMap<>();
+ if (proxy == null) {
+ proxy = getNetworkProxy(networkListener.getName());
+ }
+ if (proxy != null) {
+ if (proxy instanceof GrizzlyProxy) {
+ GrizzlyProxy grizzlyProxy = (GrizzlyProxy)proxy;
+ GenericGrizzlyListener grizzlyListener = (GenericGrizzlyListener)grizzlyProxy.getUnderlyingListener();
+ List<HttpCodecFilter> codecFilters = grizzlyListener.getFilters(HttpCodecFilter.class);
+ if (codecFilters != null && !codecFilters.isEmpty()) {
+ for (HttpCodecFilter codecFilter : codecFilters) {
+ HttpProbe[] probes = codecFilter.getMonitoringConfig().getProbes();
+ if (probes != null) {
+ List<HttpProbe> probesForType = filterToProbeMapping.get(codecFilter.getClass());
+ if (probesForType == null) {
+ probesForType = new ArrayList<>(4);
+ filterToProbeMapping.put(codecFilter.getClass(), probesForType);
+ }
+ Collections.addAll(probesForType, probes);
+ }
+ }
+ }
+ }
+
+ removeNetworkProxy(proxy);
+ }
+ final Future future = createNetworkProxy(networkListener);
+ if (future == null) {
+ LOGGER.log(Level.FINE, "Skipping proxy registration for the listener {0}",
+ networkListener.getName());
+ return;
+ }
+
+ try {
+ if (timeout <= 0) {
+ future.get();
+ } else {
+ future.get(timeout, timeUnit);
+ }
+
+ NetworkProxy newNetworkProxy = getNetworkProxy(networkListener.getName());
+ if (newNetworkProxy instanceof GrizzlyProxy) {
+ GrizzlyProxy grizzlyProxy = (GrizzlyProxy)newNetworkProxy;
+ GenericGrizzlyListener grizzlyListener = (GenericGrizzlyListener)grizzlyProxy.getUnderlyingListener();
+ if (!filterToProbeMapping.isEmpty()) {
+ for (Class<? extends HttpCodecFilter> aClass : filterToProbeMapping.keySet()) {
+ List<? extends HttpCodecFilter> filters = grizzlyListener.getFilters(aClass);
+ if (filters != null && !filters.isEmpty()) {
+ if (filters.size() != 1) {
+ throw new IllegalStateException();
+ }
+ final List<HttpProbe> probes = filterToProbeMapping.get(aClass);
+ filters.get(0).getMonitoringConfig().addProbes(probes.toArray(new HttpProbe[probes.size()]));
+ }
+ }
+ }
+ }
+ } catch (ExecutionException e) {
+ throw new IOException(e.getCause());
+ } catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+
+ registerContainerAdapters();
+ }
+
+ /**
+ * Is there any {@link MapperUpdateListener} registered?
+ */
+ public boolean hasMapperUpdateListener(){
+ return !mapperUpdateListeners.isEmpty();
+ }
+
+ /**
+ * Adds {@link MapperUpdateListener} to listeners queue.
+ *
+ * @param listener the listener to be added.
+ * @return <tt>true</tt>, if listener was successfully added,
+ * or <tt>false</tt> otherwise.
+ */
+ public boolean addMapperUpdateListener(MapperUpdateListener listener) {
+ return mapperUpdateListeners.add(listener);
+ }
+
+ /**
+ * Removes {@link MapperUpdateListener} to listeners queue.
+ *
+ * @param listener the listener to be removed.
+ * @return <tt>true</tt>, if listener was successfully removed,
+ * or <tt>false</tt> otherwise.
+ */
+ public boolean removeMapperUpdateListener(MapperUpdateListener listener) {
+ return mapperUpdateListeners.remove(listener);
+ }
+
+ /**
+ * Notify all {@link MapperUpdateListener}s about update happened.
+ *
+ * @param networkListener {@link NetworkListener}, which {@link Mapper} got changed
+ * @param mapper new {@link Mapper} value
+ */
+ public void notifyMapperUpdateListeners(NetworkListener networkListener,
+ Mapper mapper) {
+ final HttpService httpService = config.getHttpService();
+ for(MapperUpdateListener listener : mapperUpdateListeners) {
+ listener.update(httpService, networkListener, mapper);
+ }
+ }
+
+ /**
+ * Returns HTTP {@link Mapper} lock to prevent concurrent access to a
+ * {@link Mapper} object.
+ */
+ public ReentrantReadWriteLock obtainMapperLock() {
+ return mapperLock;
+ }
+
+ /**
+ * Gets the logger.
+ *
+ * @return the logger
+ */
+ public Logger getLogger() {
+ return LOGGER;
+ }
+
+
+ /**
+ * Gets the habitat.
+ *
+ * @return the habitat
+ */
+ public ServiceLocator getHabitat() {
+ return serviceLocator;
+ }
+
+ public GrizzlyMonitoring getMonitoring() {
+ return monitoring;
+ }
+
+ /**
+ * Return the {@link Future}, that might be used to monitor server startup state.
+ */
+ final Future<Boolean> getServerReadyFuture() {
+ return serverReadyFuture;
+ }
+
+ /**
+ * Add the {@link Callable} listener, which will be notified once server
+ * state switches to "SERVER_READY".
+ *
+ * @param listener {@link Callable} listener.
+ */
+ final void addServerReadyListener(final Callable<Void> listener) {
+ if (serverReadyFuture.isDone()) {
+ try {
+ listener.call();
+ } catch (Exception ignored) {
+ }
+
+ return;
+ }
+
+ serverReadyListeners.add(listener);
+
+ if (serverReadyFuture.isDone() && serverReadyListeners.remove(listener)) {
+ try {
+ listener.call();
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ /**
+ * Removes the {@link Callable} listener, which will be notified once server
+ * state switches to "SERVER_READY".
+ *
+ * @param listener {@link Callable} listener.
+ */
+ final boolean removeServerListener(final Callable<Void> listener) {
+ return serverReadyListeners.remove(listener);
+ }
+
+ /**
+ * Method is invoked each time Glassfish state changes.
+ */
+ @Override
+ public void event(@RestrictTo(EventTypes.SERVER_READY_NAME) EventListener.Event event) {
+ if (event.is(EventTypes.SERVER_READY)) {
+ serverReadyFuture.result(Boolean.TRUE);
+
+ Callable<Void> listener;
+ while((listener = serverReadyListeners.poll()) != null) {
+ try {
+ listener.call();
+ } catch (Exception ignored) {
+ }
+ }
+ }
+ }
+
+ /**
+ * The component has been injected with any dependency and
+ * will be placed into commission by the subsystem.
+ */
+ @Override
+ public void postConstruct() {
+ events.register(this);
+
+ final NetworkConfig networkConfig = config.getNetworkConfig();
+ configListener = new DynamicConfigListener(config, LOGGER);
+ ObservableBean bean = (ObservableBean) ConfigSupport.getImpl(networkConfig.getNetworkListeners());
+ bean.addListener(configListener);
+ bean = (ObservableBean) ConfigSupport.getImpl(config.getHttpService());
+ bean.addListener(configListener);
+ transactions.addListenerForType(SystemProperty.class, configListener);
+ configListener.setGrizzlyService(this);
+
+ try {
+ boolean isAtLeastOneProxyStarted = false;
+
+ futures = new ArrayList<Future<Result<Thread>>>();
+ for (NetworkListener listener : networkConfig.getNetworkListeners().getNetworkListener()) {
+ isAtLeastOneProxyStarted |= (createNetworkProxy(listener) != null);
+ }
+
+ if (isAtLeastOneProxyStarted) {
+ registerContainerAdapters();
+ }
+ } catch(RuntimeException e) { // So far postConstruct can not throw any other exception type
+ LOGGER.log(Level.SEVERE, KernelLoggerInfo.grizzlyCantStart, e);
+ for(NetworkProxy proxy : proxies) {
+ try {
+ proxy.stop();
+ } catch(Exception proxyStopException) {
+ LOGGER.log(Level.SEVERE, KernelLoggerInfo.grizzlyCloseException,
+ new Object[] {proxy.getPort(), proxyStopException});
+ }
+ }
+
+ throw e;
+ }
+
+ registerMonitoringStatsProviders();
+ }
+
+ @Override
+ public List<Future<Result<Thread>>> getFutures() {
+ return futures;
+ }
+
+ /*
+ * Creates a new NetworkProxy for a particular HttpListner
+ * @param listener NetworkListener
+ * @param networkConfig HttpService
+ */
+ public synchronized Future<Result<Thread>> createNetworkProxy(NetworkListener listener) {
+
+ if (!Boolean.valueOf(listener.getEnabled())) {
+ addChangeListener(listener); // in case the listener will be enabled
+
+ LOGGER.log(Level.INFO, KernelLoggerInfo.grizzlyPortDisabled,
+ new Object[]{listener.getName(), listener.getPort()});
+ return null;
+ }
+
+ // create the proxy for the port.
+ GrizzlyProxy proxy = new GrizzlyProxy(this, listener);
+
+ Future<Result<Thread>> future = null;
+
+ try {
+ proxy.initialize();
+
+ if (!isLightWeightListener(listener)) {
+ final NetworkConfig networkConfig = listener.getParent(NetworkListeners.class).getParent(NetworkConfig.class);
+ // attach all virtual servers to this port
+ for (VirtualServer vs : networkConfig.getParent(Config.class).getHttpService().getVirtualServer()) {
+ List<String> vsListeners =
+ StringUtils.parseStringList(vs.getNetworkListeners(), " ,");
+ if (vsListeners == null || vsListeners.isEmpty()
+ || vsListeners.contains(listener.getName())) {
+ if (!hosts.contains(vs.getId())) {
+ hosts.add(vs.getId());
+ }
+ }
+ }
+ addChangeListener(listener);
+ addChangeListener(listener.findThreadPool());
+ addChangeListener(listener.findTransport());
+
+ final Protocol protocol = listener.findHttpProtocol();
+ if (protocol != null) {
+ addChangeListener(protocol);
+ addChangeListener(protocol.getHttp());
+ addChangeListener(protocol.getHttp().getFileCache());
+ addChangeListener(protocol.getSsl());
+ }
+ }
+
+ future = proxy.start();
+
+ // add the new proxy to our list of proxies.
+ proxies.add(proxy);
+ } catch (Throwable e) {
+ final Future<Result<Thread>> errorFuture =
+ Futures.createReadyFuture(new Result<Thread>(e));
+ future = errorFuture;
+ } finally {
+ if (future == null) {
+ final FutureImpl<Result<Thread>> errorFuture =
+ Futures.<Result<Thread>>createUnsafeFuture();
+ errorFuture.result(new Result<Thread>(
+ new IllegalStateException("Unexpected error")));
+ future = errorFuture;
+ }
+
+ futures.add(future);
+ }
+
+ return future;
+ }
+
+ private void addChangeListener(ConfigBeanProxy bean) {
+ if(bean != null) {
+ ((ObservableBean) ConfigSupport.getImpl(bean)).addListener(configListener);
+ }
+ }
+
+
+ /*
+ * Registers all proxies
+ */
+ void registerContainerAdapters() {
+ for (org.glassfish.api.container.Adapter subAdapter :
+ serviceLocator.<org.glassfish.api.container.Adapter>getAllServices(org.glassfish.api.container.Adapter.class)) {
+ //@TODO change EndportRegistrationException processing if required
+ try {
+ if (!subAdapter.isRegistered()) {
+ registerAdapter(subAdapter);
+ subAdapter.setRegistered(true);
+ }
+ } catch(EndpointRegistrationException e) {
+ LOGGER.log(Level.WARNING,
+ KernelLoggerInfo.grizzlyEndpointRegistration, e);
+ }
+ }
+ }
+
+
+ /**
+ * The component is about to be removed from commission
+ */
+ @Override
+ public void preDestroy() {
+ for (NetworkProxy proxy : proxies) {
+ try {
+ proxy.stop();
+ } catch (IOException e) {
+ LOGGER.log(Level.WARNING, KernelLoggerInfo.grizzlyStopProxy, e);
+ }
+ }
+ unregisterMonitoringStatsProviders();
+ }
+
+ /*
+ * Registers a new endpoint (proxy implementation) for a particular
+ * context-root. All request coming with the context root will be dispatched
+ * to the proxy instance passed in.
+ * @param contextRoot for the proxy
+ * @param endpointAdapter servicing requests.
+ */
+ @Override
+ public void registerEndpoint(String contextRoot, HttpHandler endpointAdapter,
+ ApplicationContainer container) throws EndpointRegistrationException {
+
+ registerEndpoint(contextRoot, endpointAdapter, container, null);
+ }
+
+ /*
+ * Registers a new endpoint (proxy implementation) for a particular
+ * context-root. All request coming with the context root will be dispatched
+ * to the proxy instance passed in.
+ * @param contextRoot for the proxy
+ * @param endpointAdapter servicing requests.
+ * @param application container
+ * @param virtualServers comma separated list of the virtual servers
+ */
+ @Override
+ public void registerEndpoint(String contextRoot, HttpHandler endpointAdapter,
+ ApplicationContainer container, String virtualServers) throws EndpointRegistrationException {
+ List<String> virtualServerList;
+ if (virtualServers == null) {
+ virtualServerList =
+ config.getHttpService().getNonAdminVirtualServerList();
+ } else{
+ virtualServerList =
+ StringUtils.parseStringList(virtualServers, ",");
+ }
+ registerEndpoint(contextRoot, virtualServerList, endpointAdapter, container);
+ }
+
+
+ /*
+ * Registers a new endpoint (proxy implementation) for a particular
+ * context-root. All request coming with the context root will be dispatched
+ * to the proxy instance passed in.
+ * @param contextRoot for the proxy
+ * @param endpointAdapter servicing requests.
+ */
+
+ @Override
+ public void registerEndpoint(String contextRoot, Collection<String> vsServers, HttpHandler endpointAdapter,
+ ApplicationContainer container) throws EndpointRegistrationException {
+ Collection<AddressInfo> addressInfos = getAddressInfoFromVirtualServers(vsServers);
+ for (AddressInfo info : addressInfos) {
+ registerEndpoint(contextRoot, info.address, info.port, vsServers, endpointAdapter, container);
+ }
+ }
+
+ /**
+ * Registers a new endpoint for the given context root at the given port
+ * number.
+ */
+ @Override
+ public void registerEndpoint(String contextRoot, InetAddress address, int port, Collection<String> vsServers,
+ HttpHandler endpointAdapter, ApplicationContainer container) throws EndpointRegistrationException {
+ for (NetworkProxy proxy : proxies) {
+ if (proxy.getPort() == port && proxy.getAddress().equals(address)) {
+ proxy.registerEndpoint(contextRoot, vsServers, endpointAdapter, container);
+ }
+ }
+ }
+
+ /**
+ * Registers a new endpoint for the given context root at the given port
+ * number.
+ */
+// @Override
+ public void registerEndpoint(final Endpoint endpoint) throws EndpointRegistrationException {
+ final InetAddress address = endpoint.getAddress();
+ final int port = endpoint.getPort();
+
+ for (NetworkProxy proxy : proxies) {
+ if (proxy.getPort() == port && proxy.getAddress().equals(address)) {
+ proxy.registerEndpoint(endpoint);
+ }
+ }
+ }
+
+ /**
+ * Removes the context-root from our list of endpoints.
+ */
+ @Override
+ public void unregisterEndpoint(String contextRoot) throws EndpointRegistrationException {
+ unregisterEndpoint(contextRoot, null);
+ }
+
+ /**
+ * Removes the context-root from our list of endpoints.
+ */
+ @Override
+ public void unregisterEndpoint(String contextRoot,
+ ApplicationContainer app) throws EndpointRegistrationException {
+ for (NetworkProxy proxy : proxies) {
+ proxy.unregisterEndpoint(contextRoot, app);
+ }
+ }
+
+ /**
+ * Probe provider that implements each probe provider method as a
+ * no-op.
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
+ public static class NoopInvocationHandler implements InvocationHandler {
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) {
+ // Deliberate no-op
+ return null;
+ }
+ }
+
+ protected void registerMonitoringStatsProviders() {
+ monitoring.registerThreadPoolStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
+ monitoring.registerKeepAliveStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
+ monitoring.registerFileCacheStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
+ monitoring.registerConnectionQueueStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
+ }
+
+ protected void unregisterMonitoringStatsProviders() {
+ monitoring.unregisterThreadPoolStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
+ monitoring.unregisterKeepAliveStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
+ monitoring.unregisterFileCacheStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
+ monitoring.unregisterConnectionQueueStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
+ }
+
+ private void registerAdapter(org.glassfish.api.container.Adapter a) throws EndpointRegistrationException {
+ Endpoint endpoint = Endpoint.createEndpoint(a);
+ registerEndpoint(endpoint);
+ }
+
+ // get the ports from the http listeners that are associated with
+ // the virtual servers
+ private List<AddressInfo> getAddressInfoFromVirtualServers(Collection<String> virtualServers) {
+ List<AddressInfo> addressInfos = new ArrayList<AddressInfo>();
+ List<NetworkListener> networkListenerList = config.getNetworkConfig().getNetworkListeners().getNetworkListener();
+
+ for (String vs : virtualServers) {
+ VirtualServer virtualServer =
+ config.getHttpService().getVirtualServerByName(vs);
+ if (virtualServer == null) {
+ // non-existent virtual server
+ LOGGER.log(Level.WARNING, KernelLoggerInfo.grizzlyNonExistentVS, vs);
+ continue;
+ }
+ String vsNetworkListeners = virtualServer.getNetworkListeners();
+ List<String> vsNetworkListenerList =
+ StringUtils.parseStringList(vsNetworkListeners, ",");
+ if (vsNetworkListenerList != null && !vsNetworkListenerList.isEmpty()) {
+ for (String vsNetworkListener : vsNetworkListenerList) {
+ for (NetworkListener networkListener : networkListenerList) {
+ if (networkListener.getName().equals(vsNetworkListener) &&
+ Boolean.valueOf(networkListener.getEnabled())) {
+ addressInfos.add(new AddressInfo(networkListener.getAddress(),
+ networkListener.getPort()));
+ break;
+ }
+ }
+ }
+ }
+ }
+ return addressInfos;
+ }
+
+ static boolean isLightWeightListener(final NetworkListener listener) {
+ return "proxy".equalsIgnoreCase(listener.getType()) ||
+ "light-weight-listener".equalsIgnoreCase(listener.getProtocol());
+ }
+
+ // ---------------------------------------------------------- Nested Classes
+
+
+ private static final class AddressInfo {
+
+ private InetAddress address;
+ private final int port;
+
+ private AddressInfo(String address, String port) {
+ this.port = Integer.parseInt(port);
+ try {
+ this.address = InetAddress.getByName(address);
+ } catch (UnknownHostException ignore) {
+ }
+ }
+
+ } // END AddressInfo
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyUtils.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyUtils.java
new file mode 100644
index 0000000..7fb815d
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyUtils.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+/**
+ * Set of Grizzly network utilities
+ *
+ * @author Alexey Stashok
+ */
+public class GrizzlyUtils {
+ /**
+ * Reads bytes to the <code>WorkerThread</code> associated <code>ByteBuffer</code>s.
+ * Could be used to read both raw and secured data.
+ *
+ * @param key <code>SelectionKey</code>
+ * @param timeout read timeout
+ * @return number of read bytes
+ * @throws java.io.IOException
+ */
+// public static int readToWorkerThreadBuffers(SelectionKey key, int timeout) throws IOException {
+// Object attachment = key.attachment();
+// SSLEngine sslEngine = null;
+// if (attachment instanceof ThreadAttachment) {
+// sslEngine = ((ThreadAttachment) attachment).getSSLEngine();
+// }
+//
+// WorkerThread thread = (WorkerThread) Thread.currentThread();
+//
+// if (sslEngine == null) {
+// return Utils.readWithTemporarySelector(key.channel(),
+// thread.getByteBuffer(), timeout).bytesRead;
+// } else {
+// // if ssl - try to unwrap secured buffer first
+// ByteBuffer byteBuffer = thread.getByteBuffer();
+// ByteBuffer securedBuffer = thread.getInputBB();
+//
+// if (securedBuffer.position() > 0) {
+// int initialPosition = byteBuffer.position();
+// byteBuffer =
+// SSLUtils.unwrapAll(byteBuffer, securedBuffer, sslEngine);
+// int producedBytes = byteBuffer.position() - initialPosition;
+// if (producedBytes > 0) {
+// return producedBytes;
+// }
+// }
+//
+// // if no bytes were unwrapped - read more
+// return SSLUtils.doSecureRead(key.channel(), sslEngine, byteBuffer,
+// securedBuffer).bytesRead;
+// }
+// }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/HttpAdapter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/HttpAdapter.java
new file mode 100644
index 0000000..e3abeee
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/HttpAdapter.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import com.sun.enterprise.config.serverbeans.VirtualServer;
+
+/**
+ *
+ * @author oleksiys
+ */
+public interface HttpAdapter {
+ public ContainerMapper getMapper();
+ public VirtualServer getVirtualServer();
+ public String getWebAppRootPath();
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/HttpUtils.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/HttpUtils.java
new file mode 100644
index 0000000..9478e7d
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/HttpUtils.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import java.nio.ByteBuffer;
+
+import org.glassfish.grizzly.http.util.Ascii;
+
+/**
+ * Utility class for parsing ByteBuffer
+ * @author Jeanfrancois
+ */
+public class HttpUtils {
+
+
+ private final static String CSS =
+ "H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} " +
+ "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} " +
+ "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} " +
+ "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} " +
+ "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} " +
+ "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}" +
+ "A {color : black;}" +
+ "HR {color : #525D76;}";
+
+ /**
+ * Specialized utility method: find a sequence of lower case bytes inside
+ * a {@link ByteBuffer}.
+ */
+ public static int findBytes(ByteBuffer byteBuffer, byte[] b) {
+ int curPosition = byteBuffer.position();
+ int curLimit = byteBuffer.limit();
+
+ if (byteBuffer.position() == 0){
+ throw new IllegalStateException("Invalid state");
+ }
+
+ byteBuffer.position(0);
+ byteBuffer.limit(curPosition);
+ try {
+ byte first = b[0];
+ int start = 0;
+ int end = curPosition;
+
+ // Look for first char
+ int srcEnd = b.length;
+
+ for (int i = start; i <= (end - srcEnd); i++) {
+ if (Ascii.toLower(byteBuffer.get(i)) != first) continue;
+ // found first char, now look for a match
+ int myPos = i+1;
+ for (int srcPos = 1; srcPos < srcEnd; ) {
+ if (Ascii.toLower(byteBuffer.get(myPos++)) != b[srcPos++])
+ break;
+ if (srcPos == srcEnd) return i - start; // found it
+ }
+ }
+ return -1;
+ } finally {
+ byteBuffer.limit(curLimit);
+ byteBuffer.position(curPosition);
+ }
+ }
+
+ public static String getErrorPage(String serverName, String message, String errorCode) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" ");
+ sb.append("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
+ sb.append("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>GlassFish v4 - Error report</title><style type=\"");
+ sb.append("text/css\"><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;}");
+ sb.append(" H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;}");
+ sb.append(" H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;}");
+ sb.append(" BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} ");
+ sb.append(" B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P");
+ sb.append("{font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A");
+ sb.append(" {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status ");
+ sb.append(errorCode).append(" - ");
+ sb.append("</h1><hr/><p><b>type</b> Status report</p><p><b>message</b></p><p><b>description</b>");
+ sb.append(message).append("</p><hr/><h3>");
+ sb.append(serverName).append("</h3></body></html>");
+ return sb.toString();
+ }
+
+}
+
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/MapperUpdateListener.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/MapperUpdateListener.java
new file mode 100644
index 0000000..efa888d
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/MapperUpdateListener.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import com.sun.enterprise.config.serverbeans.HttpService;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.grizzly.http.server.util.Mapper;
+
+/**
+ * Listener interface for objects, which are interested in handling
+ * {@link Mapper} udpdates.
+ *
+ * @author Alexey Stashok
+ */
+public interface MapperUpdateListener {
+ void update(HttpService httpService, NetworkListener httpListener, Mapper mapper);
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/NetworkProxy.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/NetworkProxy.java
new file mode 100644
index 0000000..227bc87
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/NetworkProxy.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import com.sun.enterprise.util.Result;
+import java.io.IOException;
+import org.glassfish.grizzly.http.server.HttpHandler;
+
+import java.net.InetAddress;
+import java.util.concurrent.Future;
+
+/**
+ * Generic interface used by the GrizzlyService to start the tcp/udp/tcl stack.
+ * By default, we are starting Grizzly, but we might allow other framework to
+ * hook in and drive hk2/v3.
+ *
+ * TODO: Allow addition of other types of Container, not only Adapter but
+ * also any extension.
+ *
+ * @author Jeanfrancois Arcand
+ */
+public interface NetworkProxy extends EndpointMapper<HttpHandler>{
+
+
+ /**
+ * Stop the proxy.
+ */
+ void stop() throws IOException;
+
+
+ /**
+ * Start the proxy.
+ */
+ Future<Result<Thread>> start() throws IOException;
+
+
+ /**
+ * @return the network port upon which this <code>NetworkProxy</code> is
+ * listening on
+ */
+ int getPort();
+
+
+ /**
+ * @return the {@link InetAddress} of this <code>NetworkProxy</code>
+ */
+ InetAddress getAddress();
+
+
+ /**
+ * Destroy the proxy.
+ */
+ void destroy();
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ServiceInitializerFilter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ServiceInitializerFilter.java
new file mode 100644
index 0000000..3cc6729
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ServiceInitializerFilter.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import java.io.IOException;
+import java.nio.channels.SelectableChannel;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.glassfish.grizzly.filterchain.BaseFilter;
+import org.glassfish.grizzly.filterchain.FilterChainContext;
+import org.glassfish.grizzly.filterchain.NextAction;
+import org.glassfish.grizzly.nio.NIOConnection;
+import org.glassfish.grizzly.nio.NIOTransport;
+import org.glassfish.grizzly.nio.SelectorHandler;
+import org.glassfish.grizzly.nio.SelectorRunner;
+import org.glassfish.hk2.api.ActiveDescriptor;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.glassfish.internal.grizzly.LazyServiceInitializer;
+
+/**
+ * The {@link org.glassfish.grizzly.filterchain.Filter} implementation,
+ * which lazily initializes custom service on the first accepted connection
+ * and passes connection there.
+ *
+ * @author Vijay Ramachandran
+ */
+public class ServiceInitializerFilter extends BaseFilter {
+ private final ServiceLocator locator;
+ private volatile LazyServiceInitializer targetInitializer = null;
+ private final List<ActiveDescriptor<?>> initializerImplList;
+
+ protected final Logger logger;
+
+ private final ServiceInitializerListener listener;
+
+ private final Object LOCK_OBJ = new Object();
+// private long timeout = 60000;
+
+ public ServiceInitializerFilter(final ServiceInitializerListener listener,
+ final ServiceLocator habitat, final Logger logger) {
+ this.locator = habitat;
+
+ initializerImplList =
+ habitat.getDescriptors(BuilderHelper.createContractFilter(LazyServiceInitializer.class.getName()));
+
+ if (initializerImplList.isEmpty()) {
+ throw new IllegalStateException("NO Lazy Initializer was found for port = " +
+ listener.getPort());
+ }
+
+ this.logger = logger;
+ this.listener = listener;
+ }
+
+ @Override
+ public NextAction handleAccept(final FilterChainContext ctx) throws IOException {
+ final NIOConnection nioConnection = (NIOConnection) ctx.getConnection();
+ final SelectableChannel channel = nioConnection.getChannel();
+
+ // The LazyServiceInitializer's name we're looking for should be equal
+ // to either listener or protocol name
+ final String listenerName = listener.getName();
+ final String protocolName = listener.getNetworkListener().getProtocol();
+
+ if (targetInitializer == null) {
+ synchronized (LOCK_OBJ) {
+ if (targetInitializer == null) {
+ LazyServiceInitializer targetInitializerLocal = null;
+ for (final ActiveDescriptor<?> initializer : initializerImplList) {
+ String serviceName = initializer.getName();
+
+
+ if (serviceName != null &&
+ (listenerName.equalsIgnoreCase(serviceName) ||
+ protocolName.equalsIgnoreCase(serviceName))) {
+ targetInitializerLocal = (LazyServiceInitializer) locator.getServiceHandle(initializer).getService();
+ break;
+ }
+ }
+
+ if (targetInitializerLocal == null) {
+ logger.log(Level.SEVERE, "NO Lazy Initialiser implementation was found for port = {0}",
+ String.valueOf(listener.getPort()));
+ nioConnection.close();
+
+ return ctx.getStopAction();
+ }
+ if (!targetInitializerLocal.initializeService()) {
+ logger.log(Level.SEVERE, "Lazy Service initialization failed for port = {0}",
+ String.valueOf(listener.getPort()));
+
+ nioConnection.close();
+
+ return ctx.getStopAction();
+ }
+
+ targetInitializer = targetInitializerLocal;
+ }
+ }
+ }
+
+ final NextAction nextAction = ctx.getSuspendAction();
+ ctx.completeAndRecycle();
+
+ // Deregister channel
+ final SelectorRunner runner = nioConnection.getSelectorRunner();
+ final SelectorHandler selectorHandler =
+ ((NIOTransport) nioConnection.getTransport()).getSelectorHandler();
+
+ selectorHandler.deregisterChannel(runner, channel);
+
+ // Underlying service rely the channel is blocking
+ channel.configureBlocking(true);
+ targetInitializer.handleRequest(channel);
+
+ return nextAction;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ServiceInitializerListener.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ServiceInitializerListener.java
new file mode 100644
index 0000000..fad9cf8
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ServiceInitializerListener.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import java.util.logging.Logger;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+
+import org.glassfish.grizzly.config.dom.Protocol;
+import org.glassfish.grizzly.config.dom.ThreadPool;
+import org.glassfish.grizzly.config.dom.Transport;
+import org.glassfish.grizzly.filterchain.FilterChainBuilder;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;
+import org.glassfish.grizzly.strategies.SameThreadIOStrategy;
+import org.glassfish.grizzly.threadpool.GrizzlyExecutorService;
+import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
+import org.glassfish.hk2.api.ServiceLocator;
+
+/**
+ * This class extends Grizzly's GrizzlyServiceListener class to customize it for GlassFish and enable a single listener
+ * do both lazy service initialization as well as init of HTTP and admin listeners
+ *
+ * @author Vijay Ramachandran
+ * @author Alexey Stashok
+ */
+public class ServiceInitializerListener extends org.glassfish.grizzly.config.GenericGrizzlyListener {
+ private final Logger logger;
+ private final GrizzlyService grizzlyService;
+ private final NetworkListener networkListener;
+
+ public ServiceInitializerListener(final GrizzlyService grizzlyService,
+ final NetworkListener networkListener,
+ final Logger logger) {
+ this.grizzlyService = grizzlyService;
+ this.networkListener = networkListener;
+ this.logger = logger;
+ }
+
+ public NetworkListener getNetworkListener() {
+ return networkListener;
+ }
+
+ @Override
+ protected void configureTransport(final NetworkListener networkListener,
+ final Transport transportConfig,
+ final FilterChainBuilder filterChainBuilder) {
+
+ transport = configureDefaultThreadPoolConfigs(
+ TCPNIOTransportBuilder.newInstance().build());
+
+ final int acceptorThreads = transportConfig != null
+ ? Integer.parseInt(transportConfig.getAcceptorThreads())
+ : Transport.ACCEPTOR_THREADS;
+
+ transport.setSelectorRunnersCount(acceptorThreads);
+ transport.getKernelThreadPoolConfig().setPoolName(networkListener.getName() + "-kernel");
+
+ if (acceptorThreads > 0) {
+ transport.getKernelThreadPoolConfig()
+ .setCorePoolSize(acceptorThreads)
+ .setMaxPoolSize(acceptorThreads);
+ }
+
+ rootFilterChain = FilterChainBuilder.stateless().build();
+
+ transport.setProcessor(rootFilterChain);
+ transport.setIOStrategy(SameThreadIOStrategy.getInstance());
+ }
+
+
+ @Override
+ protected void configureProtocol(final ServiceLocator habitat,
+ final NetworkListener networkListener,
+ final Protocol protocol, final FilterChainBuilder filterChainBuilder) {
+ filterChainBuilder.add(new ServiceInitializerFilter(this,
+ grizzlyService.getHabitat(), logger));
+ }
+
+ @Override
+ protected void configureThreadPool(final ServiceLocator habitat,
+ final NetworkListener networkListener,
+ final ThreadPool threadPool) {
+
+ // we don't need worker thread pool
+ transport.setWorkerThreadPoolConfig(null);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/SnifferAdapter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/SnifferAdapter.java
new file mode 100644
index 0000000..9518df2
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/SnifferAdapter.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl;
+
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.v3.server.ContainerStarter;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import org.glassfish.api.container.Sniffer;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.util.MappingData;
+import org.glassfish.grizzly.http.util.DataChunk;
+import org.glassfish.hk2.api.PerLookup;
+import org.glassfish.internal.data.ContainerRegistry;
+import org.glassfish.internal.data.EngineInfo;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * These adapters are temporarily registered to the mapper to handle static
+ * pages request that a container would like to process rather than serving
+ * them statically unchanged. This is useful for things like .jsp or .php
+ * files saved in the context root of the application server.
+ *
+ * @author Jerome Dochez
+ * @author Jeanfrancois Arcand
+ */
+@Service
+@PerLookup
+public class SnifferAdapter extends HttpHandler {
+
+ @Inject
+ ContainerRegistry containerRegistry;
+
+ @Inject
+ ContainerStarter containerStarter;
+
+ @Inject
+ ModulesRegistry modulesRegistry;
+
+ private static final Logger LOGGER = KernelLoggerInfo.getLogger();
+
+ private Sniffer sniffer;
+ private ContainerMapper mapper;
+ private HttpHandler adapter;
+
+ public void initialize(Sniffer sniffer, ContainerMapper mapper) {
+ this.sniffer = sniffer;
+ this.mapper = mapper;
+ }
+
+ // I could synchronize this method since I only start one container and do it
+ // synchronously but that seems like an overkill and I would still need to handle
+ // pending requests.
+ @Override
+ public void service(Request req, Response resp) throws Exception {
+
+ if (adapter != null) {
+ // this is not supposed to happen, however due to multiple requests coming in, I would
+ // not be surprised...
+ adapter.service(req, resp);
+ return;
+ }
+
+ // bingo, we found a sniffer that wants to handle this requested
+ // page, let's get to the container or start it.
+ // start all the containers associated with sniffers.
+
+ // need to synchronize on the registry to not end up starting the same container from
+ // different threads.
+ synchronized (containerRegistry) {
+ if (adapter != null) {
+ // I got started in the meantime
+ adapter.service(req, resp);
+ return;
+ }
+
+ if (containerRegistry.getContainer(sniffer.getContainersNames()[0]) != null) {
+ LOGGER.fine("Container is claimed to be started...");
+ containerRegistry.getContainer(sniffer.getContainersNames()[0]).getContainer();
+ } else {
+ final long startTime = System.currentTimeMillis();
+ LOGGER.log(Level.INFO, KernelLoggerInfo.snifferAdapterStartingContainer, sniffer.getModuleType());
+ try {
+ Collection<EngineInfo> containersInfo = containerStarter.startContainer(sniffer);
+ if (containersInfo != null && !containersInfo.isEmpty()) {
+ // force the start on each container
+ for (EngineInfo info : containersInfo) {
+ if (LOGGER.isLoggable(Level.FINE)) {
+ LOGGER.log(Level.FINE, "Got container, deployer is {0}", info.getDeployer());
+ }
+ info.getContainer();
+ LOGGER.log(Level.INFO, KernelLoggerInfo.snifferAdapterContainerStarted,
+ new Object[]{sniffer.getModuleType(), System.currentTimeMillis() - startTime});
+ }
+ } else {
+ LOGGER.severe(KernelLoggerInfo.snifferAdapterNoContainer);
+ }
+ } catch (Exception e) {
+ LOGGER.log(Level.SEVERE,
+ KernelLoggerInfo.snifferAdapterExceptionStarting,
+ new Object[] { sniffer.getContainersNames()[0], e });
+ }
+ }
+
+ // at this point the post construct should have been called.
+ // seems like there is some possibility that the container is not synchronously started
+ // preventing the calls below to succeed...
+ DataChunk decodedURI = req.getRequest().getRequestURIRef().getDecodedRequestURIBC();
+ try {
+ // Clear the previous mapped information.
+ MappingData mappingData = (MappingData) req.getNote(ContainerMapper.MAPPING_DATA);
+ mappingData.recycle();
+
+ adapter = mapper.mapUriWithSemicolon(req, decodedURI, 0, null);
+ // If a SnifferAdapter doesn't do it's job, avoid recursion
+ // and throw a Runtime exception.
+ if (adapter.equals(this)) {
+ adapter = null;
+ throw new RuntimeException("SnifferAdapter cannot map themself.");
+ }
+ } catch (Exception e) {
+ LOGGER.log(Level.SEVERE, KernelLoggerInfo.snifferAdapterExceptionMapping, e);
+ throw e;
+ }
+
+ // pass on,,,
+ if (adapter != null) {
+ adapter.service(req, resp);
+ } else {
+ throw new RuntimeException("No Adapter found.");
+ }
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ConnectionMonitor.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ConnectionMonitor.java
new file mode 100644
index 0000000..8f8dcba
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ConnectionMonitor.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor;
+
+import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.Connection;
+import org.glassfish.grizzly.ConnectionProbe;
+import org.glassfish.grizzly.IOEvent;
+import org.glassfish.grizzly.Transport;
+
+/**
+ *
+ * @author oleksiys
+ */
+public class ConnectionMonitor implements ConnectionProbe {
+ private final GrizzlyMonitoring grizzlyMonitoring;
+ private final String monitoringId;
+
+ public ConnectionMonitor(GrizzlyMonitoring grizzlyMonitoring,
+ String monitoringId, Transport transport) {
+ this.grizzlyMonitoring = grizzlyMonitoring;
+ this.monitoringId = monitoringId;
+ }
+
+ @Override
+ public void onAcceptEvent(final Connection serverConnection,
+ final Connection clientConnection) {
+ final Object peerAddress = clientConnection.getPeerAddress();
+
+ grizzlyMonitoring.getConnectionQueueProbeProvider().connectionAcceptedEvent(
+ monitoringId, clientConnection.hashCode(),
+ peerAddress.toString());
+ }
+
+ @Override
+ public void onConnectEvent(final Connection connection) {
+ grizzlyMonitoring.getConnectionQueueProbeProvider().connectionConnectedEvent(
+ monitoringId, connection.hashCode(),
+ connection.getPeerAddress().toString());
+ }
+
+ @Override
+ public void onCloseEvent(Connection connection) {
+ grizzlyMonitoring.getConnectionQueueProbeProvider().connectionClosedEvent(
+ monitoringId, connection.hashCode());
+ }
+
+ @Override
+ public void onBindEvent(Connection connection) {
+ }
+
+ @Override
+ public void onReadEvent(Connection connection, Buffer data, int size) {
+ }
+
+ @Override
+ public void onWriteEvent(Connection connection, Buffer data, long size) {
+ }
+
+ @Override
+ public void onErrorEvent(Connection connection, Throwable error) {
+ }
+
+ @Override
+ public void onIOEventReadyEvent(Connection connection, IOEvent ioEvent) {
+ }
+
+ @Override
+ public void onIOEventEnableEvent(Connection connection, IOEvent ioEvent) {
+ }
+
+ @Override
+ public void onIOEventDisableEvent(Connection connection, IOEvent ioEvent) {
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/FileCacheMonitor.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/FileCacheMonitor.java
new file mode 100644
index 0000000..5826093
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/FileCacheMonitor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor;
+
+import com.sun.enterprise.v3.services.impl.monitor.stats.FileCacheStatsProvider;
+import org.glassfish.grizzly.http.server.filecache.FileCache;
+import org.glassfish.grizzly.http.server.filecache.FileCacheEntry;
+import org.glassfish.grizzly.http.server.filecache.FileCacheProbe;
+
+/**
+ *
+ * @author oleksiys
+ */
+public class FileCacheMonitor implements FileCacheProbe {
+ private final GrizzlyMonitoring grizzlyMonitoring;
+ private final String monitoringId;
+
+ public FileCacheMonitor(GrizzlyMonitoring grizzlyMonitoring,
+ String monitoringId, FileCache config) {
+ this.grizzlyMonitoring = grizzlyMonitoring;
+ this.monitoringId = monitoringId;
+
+ if (grizzlyMonitoring != null) {
+ final FileCacheStatsProvider statsProvider =
+ grizzlyMonitoring.getFileCacheStatsProvider(monitoringId);
+ if (statsProvider != null) {
+ statsProvider.setStatsObject(config);
+ }
+
+// statsProvider.reset();
+ }
+ }
+
+ @Override
+ public void onEntryAddedEvent(final FileCache fileCache, final FileCacheEntry entry) {
+ grizzlyMonitoring.getFileCacheProbeProvider().incOpenCacheEntriesEvent(monitoringId);
+ switch (entry.type) {
+ case HEAP: {
+ grizzlyMonitoring.getFileCacheProbeProvider().addHeapSizeEvent(monitoringId, entry.getFileSize(false));
+ break;
+ }
+ case MAPPED: {
+ grizzlyMonitoring.getFileCacheProbeProvider().addMappedMemorySizeEvent(monitoringId, entry.getFileSize(false));
+ break;
+ }
+ default: {
+ throw new IllegalStateException("Unexpected type: " + entry.type);
+ }
+ }
+
+ }
+
+ @Override
+ public void onEntryRemovedEvent(final FileCache fileCache, final FileCacheEntry entry) {
+ grizzlyMonitoring.getFileCacheProbeProvider().decOpenCacheEntriesEvent(monitoringId);
+ switch (entry.type) {
+ case HEAP: {
+ grizzlyMonitoring.getFileCacheProbeProvider().subHeapSizeEvent(monitoringId, entry.getFileSize(false));
+ break;
+ }
+ case MAPPED: {
+ grizzlyMonitoring.getFileCacheProbeProvider().subMappedMemorySizeEvent(monitoringId, entry.getFileSize(false));
+ break;
+ }
+ default: {
+ throw new IllegalStateException("Unexpected type: " + entry.type);
+ }
+ }
+ }
+
+ @Override
+ public void onEntryHitEvent(final FileCache fileCache, final FileCacheEntry entry) {
+ grizzlyMonitoring.getFileCacheProbeProvider().countHitEvent(monitoringId);
+
+ switch (entry.type) {
+ case HEAP: {
+ grizzlyMonitoring.getFileCacheProbeProvider().countInfoHitEvent(monitoringId);
+ break;
+ }
+ case MAPPED: {
+ grizzlyMonitoring.getFileCacheProbeProvider().countContentHitEvent(monitoringId);
+ break;
+ }
+ default: {
+ throw new IllegalStateException("Unexpected type: " + entry.type);
+ }
+ }
+ }
+
+ @Override
+ public void onEntryMissedEvent(final FileCache fileCache, final String host, final String requestURI) {
+ grizzlyMonitoring.getFileCacheProbeProvider().countMissEvent(monitoringId);
+ }
+
+ @Override
+ public void onErrorEvent(final FileCache fileCache, final Throwable error) {
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/GrizzlyMonitoring.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/GrizzlyMonitoring.java
new file mode 100644
index 0000000..1907b81
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/GrizzlyMonitoring.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor;
+
+import com.sun.enterprise.v3.services.impl.monitor.probes.ConnectionQueueProbeProvider;
+import com.sun.enterprise.v3.services.impl.monitor.probes.FileCacheProbeProvider;
+import com.sun.enterprise.v3.services.impl.monitor.probes.KeepAliveProbeProvider;
+import com.sun.enterprise.v3.services.impl.monitor.probes.ThreadPoolProbeProvider;
+import com.sun.enterprise.v3.services.impl.monitor.stats.ConnectionQueueStatsProvider;
+import com.sun.enterprise.v3.services.impl.monitor.stats.ConnectionQueueStatsProviderGlobal;
+import com.sun.enterprise.v3.services.impl.monitor.stats.FileCacheStatsProvider;
+import com.sun.enterprise.v3.services.impl.monitor.stats.FileCacheStatsProviderGlobal;
+import com.sun.enterprise.v3.services.impl.monitor.stats.KeepAliveStatsProvider;
+import com.sun.enterprise.v3.services.impl.monitor.stats.KeepAliveStatsProviderGlobal;
+import com.sun.enterprise.v3.services.impl.monitor.stats.ThreadPoolStatsProvider;
+import com.sun.enterprise.v3.services.impl.monitor.stats.ThreadPoolStatsProviderGlobal;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.glassfish.external.probe.provider.PluginPoint;
+import org.glassfish.external.probe.provider.StatsProviderManager;
+
+/**
+ * Grizzly monitoring manager, which is responsible for registering, unregistering
+ * Grizzly statistics probes.
+ *
+ * @author Alexey Stashok
+ */
+public class GrizzlyMonitoring {
+ private static final String CONFIG_ELEMENT = "http-service";
+
+ // network-listener->thread-pool-stats Map
+ private final Map<String, ThreadPoolStatsProvider> threadPoolStatsProvidersMap =
+ new ConcurrentHashMap<String, ThreadPoolStatsProvider>();
+ // network-listener->file-cache-stats Map
+ private final Map<String, FileCacheStatsProvider> fileCacheStatsProvidersMap =
+ new ConcurrentHashMap<String, FileCacheStatsProvider>();
+ // network-listener->keep-alive-stats Map
+ private final Map<String, KeepAliveStatsProvider> keepAliveStatsProvidersMap =
+ new ConcurrentHashMap<String, KeepAliveStatsProvider>();
+ // network-listener->connection-queue-stats Map
+ private final Map<String, ConnectionQueueStatsProvider> connectionQueueStatsProvidersMap =
+ new ConcurrentHashMap<String, ConnectionQueueStatsProvider>();
+
+ // thread-pool emitter probe
+ private final ThreadPoolProbeProvider threadPoolProbeProvider;
+ // file-cache emitter probe
+ private final FileCacheProbeProvider fileCacheProbeProvider;
+ // keep-alive emitter probe
+ private final KeepAliveProbeProvider keepAliveProbeProvider;
+ // connection queue emitter probe
+ private final ConnectionQueueProbeProvider connectionQueueProbeProvider;
+
+ public GrizzlyMonitoring() {
+ threadPoolProbeProvider = new ThreadPoolProbeProvider();
+ fileCacheProbeProvider = new FileCacheProbeProvider();
+ keepAliveProbeProvider = new KeepAliveProbeProvider();
+ connectionQueueProbeProvider = new ConnectionQueueProbeProvider();
+ }
+
+ /**
+ * Get thread-pool probe provider
+ *
+ * @return thread-pool probe provider
+ */
+ public ThreadPoolProbeProvider getThreadPoolProbeProvider() {
+ return threadPoolProbeProvider;
+ }
+
+ /**
+ * Get file-cache probe provider
+ *
+ * @return file-cache probe provider
+ */
+ public FileCacheProbeProvider getFileCacheProbeProvider() {
+ return fileCacheProbeProvider;
+ }
+
+ /**
+ * Get keep-alive probe provider
+ *
+ * @return keep-alive probe provider
+ */
+ public KeepAliveProbeProvider getKeepAliveProbeProvider() {
+ return keepAliveProbeProvider;
+ }
+
+ /**
+ * Get connection queue probe provider
+ *
+ * @return connection queue probe provider
+ */
+ public ConnectionQueueProbeProvider getConnectionQueueProbeProvider() {
+ return connectionQueueProbeProvider;
+ }
+
+ /**
+ * Register thread-pool statistics provider for a network listener
+ *
+ * @param name network listener name
+ */
+ public void registerThreadPoolStatsProvider(String name) {
+ ThreadPoolStatsProvider threadPoolStatsProvider = new ThreadPoolStatsProvider(name);
+ ThreadPoolStatsProvider oldthreadPoolStatsProvider =
+ threadPoolStatsProvidersMap.put(name, threadPoolStatsProvider);
+
+ if (oldthreadPoolStatsProvider != null) {
+ StatsProviderManager.unregister(oldthreadPoolStatsProvider);
+ }
+
+ StatsProviderManager.register(CONFIG_ELEMENT, PluginPoint.SERVER,
+ subtreePrefix(name) + "/thread-pool", threadPoolStatsProvider);
+ }
+
+ /**
+ * Unregister thread-pool statistics provider for a network listener
+ *
+ * @param name network listener name
+ */
+ public void unregisterThreadPoolStatsProvider(String name) {
+ final ThreadPoolStatsProvider threadPoolStatsProvider =
+ threadPoolStatsProvidersMap.remove(name);
+ if (threadPoolStatsProvider != null) {
+ StatsProviderManager.unregister(threadPoolStatsProvider);
+ }
+ }
+
+ /**
+ * Register keep-alive statistics provider for a network listener
+ *
+ * @param name network listener name
+ */
+ public void registerKeepAliveStatsProvider(String name) {
+ KeepAliveStatsProvider keepAliveStatsProvider = new KeepAliveStatsProvider(name);
+ KeepAliveStatsProvider oldKeepAliveStatsProvider =
+ keepAliveStatsProvidersMap.put(name, keepAliveStatsProvider);
+
+ if (oldKeepAliveStatsProvider != null) {
+ StatsProviderManager.unregister(oldKeepAliveStatsProvider);
+ }
+
+ StatsProviderManager.register(CONFIG_ELEMENT, PluginPoint.SERVER,
+ subtreePrefix(name) + "/keep-alive", keepAliveStatsProvider);
+ }
+
+ /**
+ * Unregister keep-alive statistics provider for a network listener
+ *
+ * @param name network listener name
+ */
+ public void unregisterKeepAliveStatsProvider(String name) {
+ final KeepAliveStatsProvider keepAliveStatsProvider =
+ keepAliveStatsProvidersMap.remove(name);
+ if (keepAliveStatsProvider != null) {
+ StatsProviderManager.unregister(keepAliveStatsProvider);
+ }
+ }
+
+ /**
+ * Register file-cache statistics provider for a network listener
+ *
+ * @param name network listener name
+ */
+ public void registerFileCacheStatsProvider(String name) {
+ FileCacheStatsProvider fileCacheStatsProvider = new FileCacheStatsProvider(name);
+ FileCacheStatsProvider oldFileCacheStatsProvider =
+ fileCacheStatsProvidersMap.put(name, fileCacheStatsProvider);
+
+ if (oldFileCacheStatsProvider != null) {
+ StatsProviderManager.unregister(oldFileCacheStatsProvider);
+ }
+
+ StatsProviderManager.register(CONFIG_ELEMENT, PluginPoint.SERVER,
+ subtreePrefix(name) + "/file-cache", fileCacheStatsProvider);
+ }
+
+ /**
+ * Unregister file-cache statistics provider for a network listener
+ *
+ * @param name network listener name
+ */
+ public void unregisterFileCacheStatsProvider(String name) {
+ final FileCacheStatsProvider fileCacheStatsProvider =
+ fileCacheStatsProvidersMap.remove(name);
+ if (fileCacheStatsProvider != null) {
+ StatsProviderManager.unregister(fileCacheStatsProvider);
+ }
+ }
+
+ /**
+ * Register connection queue statistics provider for a network listener
+ *
+ * @param name network listener name
+ */
+ public void registerConnectionQueueStatsProvider(String name) {
+ ConnectionQueueStatsProvider connectionQueueStatsProvider = new ConnectionQueueStatsProvider(name);
+ ConnectionQueueStatsProvider oldConnectionQueueStatsProvider =
+ connectionQueueStatsProvidersMap.put(name, connectionQueueStatsProvider);
+
+ if (oldConnectionQueueStatsProvider != null) {
+ StatsProviderManager.unregister(oldConnectionQueueStatsProvider);
+ }
+
+ StatsProviderManager.register(CONFIG_ELEMENT, PluginPoint.SERVER,
+ subtreePrefix(name) + "/connection-queue", connectionQueueStatsProvider);
+ }
+
+ /**
+ * Unregister connection queue statistics provider for a network listener
+ *
+ * @param name network listener name
+ */
+ public void unregisterConnectionQueueStatsProvider(String name) {
+ final ConnectionQueueStatsProvider connectionQueueStatsProvider =
+ connectionQueueStatsProvidersMap.remove(name);
+ if (connectionQueueStatsProvider != null) {
+ StatsProviderManager.unregister(connectionQueueStatsProvider);
+ }
+ }
+
+ /**
+ * Register server wide thread-pool statistics provider
+ */
+ public void registerThreadPoolStatsProviderGlobal(String name) {
+ ThreadPoolStatsProvider threadPoolStatsProvider = new ThreadPoolStatsProviderGlobal(name);
+ ThreadPoolStatsProvider oldthreadPoolStatsProvider =
+ threadPoolStatsProvidersMap.put(name, threadPoolStatsProvider);
+
+ if (oldthreadPoolStatsProvider != null) {
+ StatsProviderManager.unregister(oldthreadPoolStatsProvider);
+ }
+
+ StatsProviderManager.register(CONFIG_ELEMENT, PluginPoint.SERVER,
+ subtreePrefix(name) + "/thread-pool", threadPoolStatsProvider);
+ }
+
+ /**
+ * Unregister server wide thread-pool statistics provider
+ */
+ public void unregisterThreadPoolStatsProviderGlobal(String name) {
+ final ThreadPoolStatsProvider threadPoolStatsProvider =
+ threadPoolStatsProvidersMap.remove(name);
+ if (threadPoolStatsProvider != null) {
+ StatsProviderManager.unregister(threadPoolStatsProvider);
+ }
+ }
+
+ /**
+ * Register server wide keep-alive statistics provider for a network listener
+ */
+ public void registerKeepAliveStatsProviderGlobal(String name) {
+ KeepAliveStatsProvider keepAliveStatsProvider = new KeepAliveStatsProviderGlobal(name);
+ KeepAliveStatsProvider oldKeepAliveStatsProvider =
+ keepAliveStatsProvidersMap.put(name, keepAliveStatsProvider);
+
+ if (oldKeepAliveStatsProvider != null) {
+ StatsProviderManager.unregister(oldKeepAliveStatsProvider);
+ }
+
+ StatsProviderManager.register(CONFIG_ELEMENT, PluginPoint.SERVER,
+ subtreePrefix(name) + "/keep-alive", keepAliveStatsProvider);
+ }
+
+ /**
+ * Unregister server wide keep-alive statistics provider
+ */
+ public void unregisterKeepAliveStatsProviderGlobal(String name) {
+ final KeepAliveStatsProvider keepAliveStatsProvider =
+ keepAliveStatsProvidersMap.remove(name);
+ if (keepAliveStatsProvider != null) {
+ StatsProviderManager.unregister(keepAliveStatsProvider);
+ }
+ }
+
+ /**
+ * Register server wide file-cache statistics provider for a network listener
+ */
+ public void registerFileCacheStatsProviderGlobal(String name) {
+ FileCacheStatsProvider fileCacheStatsProvider = new FileCacheStatsProviderGlobal(name);
+ FileCacheStatsProvider oldFileCacheStatsProvider =
+ fileCacheStatsProvidersMap.put(name, fileCacheStatsProvider);
+
+ if (oldFileCacheStatsProvider != null) {
+ StatsProviderManager.unregister(oldFileCacheStatsProvider);
+ }
+
+ StatsProviderManager.register(CONFIG_ELEMENT, PluginPoint.SERVER,
+ subtreePrefix(name) + "/file-cache", fileCacheStatsProvider);
+ }
+
+ /**
+ * Unregister serve wide file-cache statistics provider for a network listener
+ */
+ public void unregisterFileCacheStatsProviderGlobal(String name) {
+ final FileCacheStatsProvider fileCacheStatsProvider =
+ fileCacheStatsProvidersMap.remove(name);
+ if (fileCacheStatsProvider != null) {
+ StatsProviderManager.unregister(fileCacheStatsProvider);
+ }
+ }
+
+ /**
+ * Register server wide connection queue statistics provider for a network listener
+ */
+ public void registerConnectionQueueStatsProviderGlobal(String name) {
+ ConnectionQueueStatsProvider connectionQueueStatsProvider = new ConnectionQueueStatsProviderGlobal(name);
+ ConnectionQueueStatsProvider oldConnectionQueueStatsProvider =
+ connectionQueueStatsProvidersMap.put(name, connectionQueueStatsProvider);
+
+ if (oldConnectionQueueStatsProvider != null) {
+ StatsProviderManager.unregister(oldConnectionQueueStatsProvider);
+ }
+
+ StatsProviderManager.register(CONFIG_ELEMENT, PluginPoint.SERVER,
+ subtreePrefix(name) + "/connection-queue", connectionQueueStatsProvider);
+ }
+
+ /**
+ * Unregister server wide connection queue statistics provider for a network listener
+ */
+ public void unregisterConnectionQueueStatsProviderGlobal(String name) {
+ final ConnectionQueueStatsProvider connectionQueueStatsProvider =
+ connectionQueueStatsProvidersMap.remove(name);
+ if (connectionQueueStatsProvider != null) {
+ StatsProviderManager.unregister(connectionQueueStatsProvider);
+ }
+ }
+
+ public ConnectionQueueStatsProvider getConnectionQueueStatsProvider(String name) {
+ return connectionQueueStatsProvidersMap.get(name);
+ }
+
+ public FileCacheStatsProvider getFileCacheStatsProvider(String name) {
+ return fileCacheStatsProvidersMap.get(name);
+ }
+
+ public KeepAliveStatsProvider getKeepAliveStatsProvider(String name) {
+ return keepAliveStatsProvidersMap.get(name);
+ }
+
+ public ThreadPoolStatsProvider getThreadPoolStatsProvider(String name) {
+ return threadPoolStatsProvidersMap.get(name);
+ }
+
+ private String subtreePrefix(String name) {
+ return "network/" + name;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/KeepAliveMonitor.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/KeepAliveMonitor.java
new file mode 100644
index 0000000..b63b9c3
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/KeepAliveMonitor.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor;
+
+import com.sun.enterprise.v3.services.impl.monitor.stats.KeepAliveStatsProvider;
+import java.io.IOException;
+import org.glassfish.grizzly.Connection;
+import org.glassfish.grizzly.http.KeepAlive;
+import org.glassfish.grizzly.http.KeepAliveProbe;
+
+/**
+ *
+ * @author oleksiys
+ */
+public class KeepAliveMonitor implements KeepAliveProbe {
+ private final GrizzlyMonitoring grizzlyMonitoring;
+ private final String monitoringId;
+
+ public KeepAliveMonitor(GrizzlyMonitoring grizzlyMonitoring,
+ String monitoringId, KeepAlive config) {
+ this.grizzlyMonitoring = grizzlyMonitoring;
+ this.monitoringId = monitoringId;
+
+ if (grizzlyMonitoring != null) {
+ final KeepAliveStatsProvider statsProvider =
+ grizzlyMonitoring.getKeepAliveStatsProvider(monitoringId);
+ statsProvider.setStatsObject(config);
+ statsProvider.reset();
+ }
+ }
+
+ @Override
+ public void onConnectionAcceptEvent(final Connection connection) {
+ grizzlyMonitoring.getKeepAliveProbeProvider().incrementCountConnectionsEvent(monitoringId);
+ connection.addCloseListener(new Connection.CloseListener() {
+
+ @Override
+ public void onClosed(final Connection connection, Connection.CloseType closeType) throws IOException {
+ grizzlyMonitoring.getKeepAliveProbeProvider().decrementCountConnectionsEvent(monitoringId);
+ }
+
+ });
+ }
+
+ @Override
+ public void onHitEvent(Connection connection, int requestNumber) {
+ grizzlyMonitoring.getKeepAliveProbeProvider().incrementCountHitsEvent(monitoringId);
+ }
+
+ @Override
+ public void onRefuseEvent(Connection connection) {
+ grizzlyMonitoring.getKeepAliveProbeProvider().incrementCountRefusalsEvent(monitoringId);
+ }
+
+ @Override
+ public void onTimeoutEvent(Connection connection) {
+ grizzlyMonitoring.getKeepAliveProbeProvider().incrementCountTimeoutsEvent(monitoringId);
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ThreadPoolMonitor.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ThreadPoolMonitor.java
new file mode 100644
index 0000000..28f46e8
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/ThreadPoolMonitor.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor;
+
+import com.sun.enterprise.v3.services.impl.monitor.stats.ConnectionQueueStatsProvider;
+import com.sun.enterprise.v3.services.impl.monitor.stats.ThreadPoolStatsProvider;
+import org.glassfish.grizzly.threadpool.AbstractThreadPool;
+import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
+import org.glassfish.grizzly.threadpool.ThreadPoolProbe;
+
+/**
+ *
+ * @author oleksiys
+ */
+public class ThreadPoolMonitor implements ThreadPoolProbe {
+ private final GrizzlyMonitoring grizzlyMonitoring;
+ private final String monitoringId;
+
+ public ThreadPoolMonitor(GrizzlyMonitoring grizzlyMonitoring,
+ String monitoringId, ThreadPoolConfig config) {
+ this.grizzlyMonitoring = grizzlyMonitoring;
+ this.monitoringId = monitoringId;
+
+ if (grizzlyMonitoring != null) {
+ final ThreadPoolStatsProvider threadPoolStatsProvider =
+ grizzlyMonitoring.getThreadPoolStatsProvider(monitoringId);
+ if (threadPoolStatsProvider != null) {
+ threadPoolStatsProvider.setStatsObject(config);
+ threadPoolStatsProvider.reset();
+ }
+
+ final ConnectionQueueStatsProvider connectionQueueStatsProvider =
+ grizzlyMonitoring.getConnectionQueueStatsProvider(monitoringId);
+ if (connectionQueueStatsProvider != null) {
+ connectionQueueStatsProvider.setStatsObject(config);
+ connectionQueueStatsProvider.reset();
+ }
+ }
+ }
+
+ @Override
+ public void onThreadPoolStartEvent(AbstractThreadPool threadPool) {
+ }
+
+ @Override
+ public void onThreadPoolStopEvent(AbstractThreadPool threadPool) {
+ }
+
+ @Override
+ public void onThreadAllocateEvent(AbstractThreadPool threadPool, Thread thread) {
+ grizzlyMonitoring.getThreadPoolProbeProvider().threadAllocatedEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ thread.getId());
+ }
+
+ @Override
+ public void onThreadReleaseEvent(AbstractThreadPool threadPool, Thread thread) {
+ grizzlyMonitoring.getThreadPoolProbeProvider().threadReleasedEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ thread.getId());
+ }
+
+ @Override
+ public void onMaxNumberOfThreadsEvent(AbstractThreadPool threadPool, int maxNumberOfThreads) {
+ grizzlyMonitoring.getThreadPoolProbeProvider().maxNumberOfThreadsReachedEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ maxNumberOfThreads);
+ }
+
+ @Override
+ public void onTaskDequeueEvent(AbstractThreadPool threadPool, Runnable task) {
+ grizzlyMonitoring.getThreadPoolProbeProvider().threadDispatchedFromPoolEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ Thread.currentThread().getId());
+ grizzlyMonitoring.getConnectionQueueProbeProvider().onTaskDequeuedEvent(
+ monitoringId, task.getClass().getName());
+ }
+
+ @Override
+ public void onTaskCancelEvent(AbstractThreadPool threadPool, Runnable task) {
+ // when dequeued task is cancelled - we have to "return" the thread, that
+ // we marked as dispatched from the pool
+ grizzlyMonitoring.getThreadPoolProbeProvider().threadReturnedToPoolEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ Thread.currentThread().getId());
+ }
+
+ @Override
+ public void onTaskCompleteEvent(AbstractThreadPool threadPool, Runnable task) {
+ grizzlyMonitoring.getThreadPoolProbeProvider().threadReturnedToPoolEvent(
+ monitoringId, threadPool.getConfig().getPoolName(),
+ Thread.currentThread().getId());
+ }
+
+ @Override
+ public void onTaskQueueEvent(AbstractThreadPool threadPool, Runnable task) {
+ grizzlyMonitoring.getConnectionQueueProbeProvider().onTaskQueuedEvent(
+ monitoringId, task.getClass().getName());
+ }
+
+ @Override
+ public void onTaskQueueOverflowEvent(AbstractThreadPool threadPool) {
+ grizzlyMonitoring.getConnectionQueueProbeProvider().onTaskQueueOverflowEvent(
+ monitoringId);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ConnectionQueueProbeProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ConnectionQueueProbeProvider.java
new file mode 100644
index 0000000..e722581
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ConnectionQueueProbeProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.probes;
+
+import org.glassfish.external.probe.provider.annotations.Probe;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.external.probe.provider.annotations.ProbeProvider;
+
+/**
+ * Probe provider interface for connection queue related events.
+ *
+ * @author Alexey Stashok
+ */
+@ProbeProvider(moduleProviderName = "glassfish", moduleName = "kernel", probeProviderName = "connection-queue")
+public class ConnectionQueueProbeProvider {
+
+ @Probe(name = "connectionAcceptedEvent")
+ public void connectionAcceptedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("connection") int connectionId,
+ @ProbeParam("address") String address) {}
+
+ @Probe(name = "connectionConnectedEvent")
+ public void connectionConnectedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("connection") int connectionId,
+ @ProbeParam("address") String address) {}
+
+ @Probe(name = "connectionClosedEvent")
+ public void connectionClosedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("connection") int connectionId) {}
+
+ @Probe(name = "setMaxTaskQueueSizeEvent")
+ public void setMaxTaskQueueSizeEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("size") int size) {}
+
+ @Probe(name = "onTaskQueuedEvent")
+ public void onTaskQueuedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("task") String taskId) {}
+
+ @Probe(name = "onTaskDequeuedEvent")
+ public void onTaskDequeuedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("task") String taskId) {}
+
+ @Probe(name = "onTaskQueueOverflowEvent")
+ public void onTaskQueueOverflowEvent(
+ @ProbeParam("listenerName") String listenerName) {}
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/FileCacheProbeProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/FileCacheProbeProvider.java
new file mode 100644
index 0000000..fcc4246
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/FileCacheProbeProvider.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.probes;
+
+import org.glassfish.external.probe.provider.annotations.Probe;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.external.probe.provider.annotations.ProbeProvider;
+
+/**
+ * Probe provider interface for file-cache related events.
+ *
+ * @author Alexey Stashok
+ */
+@ProbeProvider (moduleProviderName="glassfish", moduleName="kernel", probeProviderName="file-cache")
+public class FileCacheProbeProvider {
+ @Probe(name="countHitEvent")
+ public void countHitEvent(@ProbeParam("fileCacheName") String fileCacheName) {}
+
+ @Probe(name="countMissEvent")
+ public void countMissEvent(@ProbeParam("fileCacheName") String fileCacheName) {}
+
+ @Probe(name="countInfoHitEvent")
+ public void countInfoHitEvent(@ProbeParam("fileCacheName") String fileCacheName) {}
+
+ @Probe(name="countInfoMissEvent")
+ public void countInfoMissEvent(@ProbeParam("fileCacheName") String fileCacheName) {}
+
+ @Probe(name="countContentHitEvent")
+ public void countContentHitEvent(@ProbeParam("fileCacheName") String fileCacheName) {}
+
+ @Probe(name="countContentMissEvent")
+ public void countContentMissEvent(@ProbeParam("fileCacheName") String fileCacheName) {}
+
+ @Probe(name="incOpenCacheEntriesEvent")
+ public void incOpenCacheEntriesEvent(@ProbeParam("fileCacheName") String fileCacheName) {}
+
+ @Probe(name="decOpenCacheEntriesEvent")
+ public void decOpenCacheEntriesEvent(@ProbeParam("fileCacheName") String fileCacheName) {}
+
+ @Probe(name="addHeapSizeEvent")
+ public void addHeapSizeEvent(@ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {}
+
+ @Probe(name="subHeapSizeEvent")
+ public void subHeapSizeEvent(@ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {}
+
+ @Probe(name="addMappedMemorySizeEvent")
+ public void addMappedMemorySizeEvent(
+ @ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {}
+
+ @Probe(name="subMappedMemorySizeEvent")
+ public void subMappedMemorySizeEvent(
+ @ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {}
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/KeepAliveProbeProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/KeepAliveProbeProvider.java
new file mode 100644
index 0000000..b63aab3
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/KeepAliveProbeProvider.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.probes;
+
+import org.glassfish.external.probe.provider.annotations.Probe;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.external.probe.provider.annotations.ProbeProvider;
+
+/**
+ * Probe provider interface for connections keep-alive related events.
+ *
+ * @author Alexey Stashok
+ */
+@ProbeProvider (moduleProviderName="glassfish", moduleName="kernel", probeProviderName="connections-keep-alive")
+public class KeepAliveProbeProvider {
+ @Probe(name="setMaxCountRequestsEvent")
+ public void setMaxCountRequestsEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("maxRequests") int maxRequests) {}
+
+ @Probe(name="setTimeoutInSecondsEvent")
+ public void setTimeoutInSecondsEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("timeoutInSeconds") int timeoutInSeconds) {}
+
+ @Probe(name="incrementCountConnectionsEvent")
+ public void incrementCountConnectionsEvent(
+ @ProbeParam("listenerName") String listenerName) {}
+
+ @Probe(name="decrementCountConnectionsEvent")
+ public void decrementCountConnectionsEvent(
+ @ProbeParam("listenerName") String listenerName) {}
+
+ @Probe(name="incrementCountFlushesEvent")
+ public void incrementCountFlushesEvent(
+ @ProbeParam("listenerName") String listenerName) {}
+
+ @Probe(name="incrementCountHitsEvent")
+ public void incrementCountHitsEvent(
+ @ProbeParam("listenerName") String listenerName) {}
+
+ @Probe(name="incrementCountRefusalsEvent")
+ public void incrementCountRefusalsEvent(
+ @ProbeParam("listenerName") String listenerName) {}
+
+ @Probe(name="incrementCountTimeoutsEvent")
+ public void incrementCountTimeoutsEvent(
+ @ProbeParam("listenerName") String listenerName) {}
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ThreadPoolProbeProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ThreadPoolProbeProvider.java
new file mode 100644
index 0000000..fbb36cf
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/probes/ThreadPoolProbeProvider.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.probes;
+
+import org.glassfish.external.probe.provider.annotations.Probe;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.external.probe.provider.annotations.ProbeProvider;
+
+/**
+ * Probe provider interface for thread pool related events.
+ */
+@ProbeProvider (moduleProviderName="glassfish", moduleName="kernel", probeProviderName="thread-pool")
+public class ThreadPoolProbeProvider {
+
+ @Probe(name="setMaxThreadsEvent")
+ public void setMaxThreadsEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("maxNumberOfThreads") int maxNumberOfThreads) {}
+
+
+ @Probe(name="setCoreThreadsEvent")
+ public void setCoreThreadsEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("coreNumberOfThreads") int coreNumberOfThreads) {}
+
+ /**
+ * Emits notification that new thread was created and added to the
+ * thread pool.
+ */
+ @Probe(name="threadAllocatedEvent")
+ public void threadAllocatedEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {}
+
+
+ @Probe(name="threadReleasedEvent")
+ public void threadReleasedEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {}
+
+
+ @Probe(name="maxNumberOfThreadsReachedEvent")
+ public void maxNumberOfThreadsReachedEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("maxNumberOfThreads") int maxNumberOfThreads) {}
+
+
+ @Probe(name="threadDispatchedFromPoolEvent")
+ public void threadDispatchedFromPoolEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {}
+
+
+ @Probe(name="threadReturnedToPoolEvent")
+ public void threadReturnedToPoolEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {}
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ConnectionQueueStatsProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ConnectionQueueStatsProvider.java
new file mode 100644
index 0000000..fdce843
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ConnectionQueueStatsProvider.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.glassfish.external.probe.provider.annotations.ProbeListener;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.external.statistics.CountStatistic;
+import org.glassfish.external.statistics.annotations.Reset;
+import org.glassfish.external.statistics.impl.CountStatisticImpl;
+import org.glassfish.gmbal.AMXMetadata;
+import org.glassfish.gmbal.Description;
+import org.glassfish.gmbal.ManagedAttribute;
+import org.glassfish.gmbal.ManagedObject;
+import org.glassfish.grizzly.threadpool.SyncThreadPool;
+import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
+
+/**
+ * Connection Queue statistics
+ *
+ * @author Alexey Stashok
+ */
+@AMXMetadata(type = "connection-queue-mon", group = "monitoring")
+@ManagedObject
+@Description("Connection Queue Statistics")
+public class ConnectionQueueStatsProvider implements StatsProvider {
+ protected static final long MINUTE = 60 * 1000;
+
+ private final String name;
+
+ protected final CountStatisticImpl countTotalConnections = new CountStatisticImpl("CountTotalConnections", "count", "Total number of connections that have been accepted");
+ protected final Map<Integer, Long> openConnectionsCount = new ConcurrentHashMap<Integer, Long>();
+
+ protected final CountStatisticImpl countOverflows = new CountStatisticImpl("CountOverflows", "count", "Number of times the queue has been too full to accommodate a connection");
+
+ protected final AtomicInteger countQueuedAtomic = new AtomicInteger();
+ protected final CountStatisticImpl countQueued = new CountStatisticImpl("CountQueued", "count", "Number of connections currently in the queue");
+
+ protected final CountStatisticImpl countTotalQueued = new CountStatisticImpl("CountTotalQueued", "count", "Total number of connections that have been queued");
+
+ protected final CountStatisticImpl maxQueued = new CountStatisticImpl("MaxQueued", "count", "Maximum size of the connection queue");
+
+ protected final AtomicInteger peakQueuedAtomic = new AtomicInteger();
+ protected final CountStatisticImpl peakQueued = new CountStatisticImpl("PeakQueued", "count", "Largest number of connections that were in the queue simultaneously");
+
+ protected final CountStatisticImpl ticksTotalQueued = new CountStatisticImpl("TicksTotalQueued", "count", "(Unsupported) Total number of ticks that connections have spent in the queue");
+
+ protected final int[] averageStatsPerMinute = new int[15];
+ protected long averageLastShift;
+ protected int averageMinuteCounter;
+
+ protected volatile ThreadPoolConfig threadPoolConfig;
+
+ public ConnectionQueueStatsProvider(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public Object getStatsObject() {
+ return threadPoolConfig;
+ }
+
+ @Override
+ public void setStatsObject(Object object) {
+ if (object instanceof ThreadPoolConfig) {
+ threadPoolConfig = (ThreadPoolConfig) object;
+ } else {
+ threadPoolConfig = null;
+ }
+ }
+
+ @ManagedAttribute(id = "counttotalconnections")
+ @Description("Total number of connections that have been accepted")
+ public CountStatistic getTotalConnectionsCount() {
+ return countTotalConnections;
+ }
+
+ @ManagedAttribute(id = "countopenconnections")
+ @Description("The number of open/active connections")
+ public CountStatistic getOpenConnectionsCount() {
+ final CountStatisticImpl stats =
+ new CountStatisticImpl("CountOpenConnections",
+ "count", "The number of open/active connections");
+ stats.setCount(openConnectionsCount.size());
+ return stats;
+ }
+
+ @ManagedAttribute(id = "countoverflows")
+ @Description("Number of times the queue has been too full to accommodate a connection")
+ public CountStatistic getCountOverflows() {
+ return countOverflows;
+ }
+
+ @ManagedAttribute(id = "countqueued")
+ @Description("Number of connections currently in the queue")
+ public CountStatistic getCountQueued() {
+ return countQueued;
+ }
+
+ @ManagedAttribute(id = "countqueued1minuteaverage")
+ @Description("Average number of connections queued in the last 1 minute")
+ public CountStatistic getCountQueued1MinuteAverage() {
+ final CountStatisticImpl stats = new CountStatisticImpl(
+ "CountQueued1MinuteAverage", "count",
+ "Average number of connections queued in the last 1 minute");
+ stats.setCount(getAverageBy(1));
+ return stats;
+ }
+
+ @ManagedAttribute(id = "countqueued5minutesaverage")
+ @Description("Average number of connections queued in the last 5 minutes")
+ public CountStatistic getCountQueued5MinutesAverage() {
+ final CountStatisticImpl stats = new CountStatisticImpl(
+ "CountQueued5MinutesAverage", "count",
+ "Average number of connections queued in the last 5 minutes");
+ stats.setCount(getAverageBy(5));
+ return stats;
+ }
+
+ @ManagedAttribute(id = "countqueued15minutesaverage")
+ @Description("Average number of connections queued in the last 15 minutes")
+ public CountStatistic getCountQueued15MinutesAverage() {
+ final CountStatisticImpl stats = new CountStatisticImpl(
+ "CountQueued15MinutesAverage", "count",
+ "Average number of connections queued in the last 15 minutes");
+ stats.setCount(getAverageBy(15));
+ return stats;
+ }
+
+ @ManagedAttribute(id = "counttotalqueued")
+ @Description("Total number of connections that have been queued")
+ public CountStatistic getCountTotalQueued() {
+ return countTotalQueued;
+ }
+
+ @ManagedAttribute(id = "maxqueued")
+ @Description("Maximum size of the connection queue")
+ public CountStatistic getMaxQueued() {
+ return maxQueued;
+ }
+
+ @ManagedAttribute(id = "peakqueued")
+ @Description("Largest number of connections that were in the queue simultaneously")
+ public CountStatistic getPeakQueued() {
+ return peakQueued;
+ }
+
+ @ManagedAttribute(id = "tickstotalqueued")
+ @Description("(Unsupported) Total number of ticks that connections have spent in the queue")
+ public CountStatistic getTicksTotalQueued() {
+ return ticksTotalQueued;
+ }
+
+ // ---------------- Connection related listeners -----------
+ @ProbeListener("glassfish:kernel:connection-queue:connectionAcceptedEvent")
+ public void connectionAcceptedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("connection") int connectionId,
+ @ProbeParam("address") String address) {
+
+ if (name.equals(listenerName)) {
+ countTotalConnections.increment();
+ openConnectionsCount.put(connectionId, System.currentTimeMillis());
+ }
+ }
+
+// We're not interested in client connections, created via Grizzly
+// @ProbeListener("glassfish:kernel:connection-queue:connectionConnectedEvent")
+// public void connectionConnectedEvent(
+// @ProbeParam("listenerName") String listenerName,
+// @ProbeParam("connection") int connectionId,
+// @ProbeParam("address") String address) {
+// }
+ @ProbeListener("glassfish:kernel:connection-queue:connectionClosedEvent")
+ public void connectionClosedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("connection") int connectionId) {
+ if (name.equals(listenerName)) {
+ openConnectionsCount.remove(connectionId);
+ }
+ }
+
+ // -----------------------------------------------------------------------
+
+ @ProbeListener("glassfish:kernel:connection-queue:setMaxTaskQueueSizeEvent")
+ public void setMaxTaskQueueSizeEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("size") int size) {
+ if (name.equals(listenerName)) {
+ maxQueued.setCount(size);
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:connection-queue:onTaskQueuedEvent")
+ public void onTaskQueuedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("task") String taskId) {
+ if (name.equals(listenerName)) {
+ final int queued = countQueuedAtomic.incrementAndGet();
+ countQueued.setCount(queued);
+
+ do {
+ final int peakQueue = peakQueuedAtomic.get();
+ if (queued <= peakQueue) break;
+
+ if (peakQueuedAtomic.compareAndSet(peakQueue, queued)) {
+ synchronized (peakQueuedAtomic) {
+ peakQueued.setCount(peakQueuedAtomic.get());
+ break;
+ }
+ }
+ } while (true);
+
+ countTotalQueued.increment();
+
+ incAverageMinute();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:connection-queue:onTaskDequeuedEvent")
+ public void onTaskDequeuedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("task") String taskId) {
+ if (name.equals(listenerName)) {
+ countQueued.setCount(countQueuedAtomic.decrementAndGet());
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:connection-queue:onTaskQueueOverflowEvent")
+ public void onTaskQueueOverflowEvent(
+ @ProbeParam("listenerName") String listenerName) {
+ if (name.equals(listenerName)) {
+ countOverflows.increment();
+ }
+ }
+
+ protected void incAverageMinute() {
+ synchronized(averageStatsPerMinute) {
+ final long currentTime = System.currentTimeMillis();
+ if (currentTime - averageLastShift >= MINUTE) {
+ shiftAverage(currentTime);
+ }
+
+ averageMinuteCounter++;
+ }
+ }
+
+ protected int getAverageBy(int mins) {
+ synchronized(averageStatsPerMinute) {
+ final long currentTime = System.currentTimeMillis();
+ if (currentTime - averageLastShift >= MINUTE) {
+ shiftAverage(currentTime);
+ }
+
+ int result = 0;
+ final int statsToCount = Math.min(mins, averageStatsPerMinute.length);
+ for(int i = 0; i < statsToCount; i++) {
+ result += averageStatsPerMinute[i];
+ }
+
+ return result;
+ }
+ }
+
+ private void shiftAverage(long currentTime) {
+ final int shift = (int) ((currentTime - averageLastShift) / MINUTE);
+ if (shift == 0) {
+ return;
+ }
+
+ final int statsSize = averageStatsPerMinute.length;
+ for(int i = statsSize - 1; i >= 0; i--) {
+ final int newIndex = shift + i;
+ if (newIndex < statsSize) {
+ averageStatsPerMinute[newIndex] = averageStatsPerMinute[i];
+ }
+
+ averageStatsPerMinute[i] = 0;
+ }
+
+ if (shift <= statsSize) {
+ averageStatsPerMinute[shift - 1] = averageMinuteCounter;
+ }
+
+ averageMinuteCounter = 0;
+ averageLastShift += (shift * MINUTE);
+ }
+
+ @Reset
+ public void reset() {
+ countTotalConnections.setCount(0);
+ openConnectionsCount.clear();
+ countOverflows.setCount(0);
+
+ countQueuedAtomic.set(0);
+ countQueued.setCount(0);
+
+ countTotalQueued.setCount(0);
+ if (threadPoolConfig != null) {
+ maxQueued.setCount(threadPoolConfig.getQueueLimit());
+ }
+
+ peakQueuedAtomic.set(0);
+ peakQueued.setCount(0);
+
+ ticksTotalQueued.setCount(0);
+
+ averageLastShift = 0;
+ averageMinuteCounter = 0;
+
+ for (int i = 0; i < averageStatsPerMinute.length; i++) {
+ averageStatsPerMinute[i] = 0;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ConnectionQueueStatsProviderGlobal.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ConnectionQueueStatsProviderGlobal.java
new file mode 100644
index 0000000..823f779
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ConnectionQueueStatsProviderGlobal.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+import org.glassfish.external.probe.provider.annotations.ProbeListener;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.gmbal.AMXMetadata;
+import org.glassfish.gmbal.Description;
+import org.glassfish.gmbal.ManagedObject;
+
+/**
+ * Server wide Connection Queue statistics
+ *
+ * @author Amy Roh
+ */
+@AMXMetadata(type = "connection-queue-mon", group = "monitoring")
+@ManagedObject
+@Description("Connection Queue Statistics")
+public class ConnectionQueueStatsProviderGlobal extends ConnectionQueueStatsProvider {
+
+ public ConnectionQueueStatsProviderGlobal(String name) {
+ super(name);
+ }
+
+ // ---------------- Connection related listeners -----------
+ @ProbeListener("glassfish:kernel:connection-queue:connectionAcceptedEvent")
+ public void connectionAcceptedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("connection") int connectionId,
+ @ProbeParam("address") String address) {
+ countTotalConnections.increment();
+ openConnectionsCount.put(connectionId, System.currentTimeMillis());
+ }
+
+ @ProbeListener("glassfish:kernel:connection-queue:connectionClosedEvent")
+ public void connectionClosedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("connection") int connectionId) {
+ openConnectionsCount.remove(connectionId);
+ }
+
+ // -----------------------------------------------------------------------
+
+ @ProbeListener("glassfish:kernel:connection-queue:setMaxTaskQueueSizeEvent")
+ public void setMaxTaskQueueSizeEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("size") int size) {
+ maxQueued.setCount(size);
+ }
+
+ @ProbeListener("glassfish:kernel:connection-queue:onTaskQueuedEvent")
+ public void onTaskQueuedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("task") String taskId) {
+ final int queued = countQueuedAtomic.incrementAndGet();
+ countQueued.setCount(queued);
+
+ do {
+ final int peakQueue = peakQueuedAtomic.get();
+ if (queued <= peakQueue) break;
+
+ if (peakQueuedAtomic.compareAndSet(peakQueue, queued)) {
+ peakQueued.setCount(queued);
+ break;
+ }
+ } while (true);
+
+ countTotalQueued.increment();
+
+ incAverageMinute();
+ }
+
+ @ProbeListener("glassfish:kernel:connection-queue:onTaskDequeuedEvent")
+ public void onTaskDequeuedEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("task") String taskId) {
+ countQueued.setCount(countQueuedAtomic.decrementAndGet());
+ }
+
+ @ProbeListener("glassfish:kernel:connection-queue:onTaskQueueOverflowEvent")
+ public void onTaskQueueOverflowEvent(
+ @ProbeParam("listenerName") String listenerName) {
+ countOverflows.increment();
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/FileCacheStatsProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/FileCacheStatsProvider.java
new file mode 100644
index 0000000..19c879b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/FileCacheStatsProvider.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+import java.util.concurrent.atomic.AtomicLong;
+import org.glassfish.external.probe.provider.annotations.ProbeListener;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.external.statistics.CountStatistic;
+import org.glassfish.external.statistics.impl.CountStatisticImpl;
+import org.glassfish.gmbal.AMXMetadata;
+import org.glassfish.gmbal.Description;
+import org.glassfish.gmbal.ManagedAttribute;
+import org.glassfish.gmbal.ManagedObject;
+import org.glassfish.grizzly.http.server.filecache.FileCache;
+
+/**
+ * File cache statistics
+ *
+ * @author Alexey Stashok
+ */
+@AMXMetadata(type="file-cache-mon", group="monitoring")
+@ManagedObject
+@Description("File Cache Statistics")
+public class FileCacheStatsProvider implements StatsProvider {
+
+ private final String name;
+
+ protected final CountStatisticImpl hitsCount = new CountStatisticImpl("HitsCount", "count" , "Number of cache lookup hits");
+ protected final CountStatisticImpl missesCount = new CountStatisticImpl("MissesCount", "count", "Number of cache lookup misses");
+ protected final CountStatisticImpl infoHitsCount = new CountStatisticImpl("InfoHitsCount", "count", "Number of hits on cached file info");
+ protected final CountStatisticImpl infoMissesCount = new CountStatisticImpl("InfoMissesCount", "count", "Number of misses on cached file info");
+ protected final CountStatisticImpl contentHitsCount = new CountStatisticImpl("ContentHitsCount", "count", "Number of hits on cached file content");
+ protected final CountStatisticImpl contentMissesCount = new CountStatisticImpl("ContentMissesCount", "count", "Number of misses on cached file content");
+
+ protected final CountStatisticImpl openCacheEntriesCount = new CountStatisticImpl("OpenCacheEntriesCount", "count", "Number of current open cache entries");
+ protected final AtomicLong heapSize = new AtomicLong();
+ protected final AtomicLong mappedMemorySize = new AtomicLong();
+
+ protected final AtomicLong maxHeapSize = new AtomicLong();
+ protected final AtomicLong maxMappedMemorySize = new AtomicLong();
+
+ protected volatile FileCache fileCache;
+
+ public FileCacheStatsProvider(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public Object getStatsObject() {
+ return fileCache;
+ }
+
+ @Override
+ public void setStatsObject(Object object) {
+ if (object instanceof FileCache) {
+ fileCache = (FileCache) object;
+ } else {
+ fileCache = null;
+ }
+ }
+
+ @ManagedAttribute(id = "hits")
+ @Description("Number of cache lookup hits")
+ public CountStatistic getHitsCount() {
+ return hitsCount;
+ }
+
+ @ManagedAttribute(id = "misses")
+ @Description("Number of cache lookup misses")
+ public CountStatistic getMissesCount() {
+ return missesCount;
+ }
+
+ @ManagedAttribute(id = "infohits")
+ @Description("Number of hits on cached file info")
+ public CountStatistic getInfoHitsCount() {
+ return infoHitsCount;
+ }
+
+ @ManagedAttribute(id = "infomisses")
+ @Description("Number of misses on cached file info")
+ public CountStatistic getInfoMissesCount() {
+ return infoMissesCount;
+ }
+
+ @ManagedAttribute(id = "contenthits")
+ @Description("Number of hits on cached file content")
+ public CountStatistic getContentHitsCount() {
+ return contentHitsCount;
+ }
+
+ @ManagedAttribute(id = "contentmisses")
+ @Description("Number of misses on cached file content")
+ public CountStatistic getContentMissesCount() {
+ return contentMissesCount;
+ }
+
+ @ManagedAttribute(id = "opencacheentries")
+ @Description("Number of current open cache entries")
+ public CountStatistic getOpenCacheEntriesCount() {
+ return openCacheEntriesCount;
+ }
+
+ @ManagedAttribute(id = "heapsize")
+ @Description("Current cache size in bytes")
+ public CountStatistic getHeapSize() {
+ final CountStatisticImpl stats = new CountStatisticImpl("HeapSize",
+ "byte(s)", "Current cache size in bytes");
+ stats.setCount(heapSize.get());
+ return stats;
+ }
+
+ @ManagedAttribute(id = "maxheapsize")
+ @Description("Maximum heap space used for cache")
+ public CountStatistic getMaxHeapSize() {
+ final CountStatisticImpl stats = new CountStatisticImpl("MaxHeapSize",
+ "byte(s)", "Maximum heap space used for cache");
+ stats.setCount(maxHeapSize.get());
+ return stats;
+ }
+
+ @ManagedAttribute(id = "mappedmemorysize")
+ @Description("Size of mapped memory used for caching")
+ public CountStatistic getMappedMemorySize() {
+ final CountStatisticImpl stats = new CountStatisticImpl(
+ "MappedMemorySize", "byte(s)",
+ "Size of mapped memory used for caching");
+ stats.setCount(mappedMemorySize.get());
+ return stats;
+ }
+
+ @ManagedAttribute(id = "maxmappedmemorysize")
+ @Description("Maximum memory map size used for caching")
+ public CountStatistic getMaxMappedMemorySize() {
+ final CountStatisticImpl stats = new CountStatisticImpl(
+ "MaxMappedMemorySize", "byte(s)",
+ "Maximum memory map size used for caching");
+ stats.setCount(maxMappedMemorySize.get());
+ return stats;
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countHitEvent")
+ public void countHitEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ if (name.equals(fileCacheName)) {
+ hitsCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countMissEvent")
+ public void countMissEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ if (name.equals(fileCacheName)) {
+ missesCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countInfoHitEvent")
+ public void countInfoHitEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ if (name.equals(fileCacheName)) {
+ infoHitsCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countInfoMissEvent")
+ public void countInfoMissEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ if (name.equals(fileCacheName)) {
+ infoMissesCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countContentHitEvent")
+ public void countContentHitEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ if (name.equals(fileCacheName)) {
+ contentHitsCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countContentMissEvent")
+ public void countContentMissEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ if (name.equals(fileCacheName)) {
+ contentMissesCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:incOpenCacheEntriesEvent")
+ public void incOpenCacheEntriesEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ if (name.equals(fileCacheName)) {
+ openCacheEntriesCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:decOpenCacheEntriesEvent")
+ public void decOpenCacheEntriesEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ if (name.equals(fileCacheName)) {
+ openCacheEntriesCount.decrement();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:addHeapSizeEvent")
+ public void addHeapSizeEvent(@ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {
+ if (name.equals(fileCacheName)) {
+ final long newSize = heapSize.addAndGet(size);
+ while (true) {
+ final long maxSize = maxHeapSize.get();
+ if (newSize > maxSize) {
+ if (maxHeapSize.compareAndSet(maxSize, newSize)) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:subHeapSizeEvent")
+ public void subHeapSizeEvent(@ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {
+ if (name.equals(fileCacheName)) {
+ heapSize.addAndGet(-size);
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:addMappedMemorySizeEvent")
+ public void addMappedMemorySizeEvent(
+ @ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {
+ if (name.equals(fileCacheName)) {
+ final long newSize = mappedMemorySize.addAndGet(size);
+ while (true) {
+ final long maxMemSize = maxMappedMemorySize.get();
+ if (newSize > maxMemSize) {
+ if (maxMappedMemorySize.compareAndSet(maxMemSize, newSize)) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:subMappedMemorySizeEvent")
+ public void subMappedMemorySizeEvent(
+ @ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {
+ if (name.equals(fileCacheName)) {
+ mappedMemorySize.addAndGet(-size);
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/FileCacheStatsProviderGlobal.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/FileCacheStatsProviderGlobal.java
new file mode 100644
index 0000000..72110b6
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/FileCacheStatsProviderGlobal.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+import org.glassfish.external.probe.provider.annotations.ProbeListener;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.gmbal.AMXMetadata;
+import org.glassfish.gmbal.Description;
+import org.glassfish.gmbal.ManagedObject;
+
+/**
+ * Server wide File cache statistics
+ *
+ * @author Amy Roh
+ */
+@AMXMetadata(type="file-cache-mon", group="monitoring")
+@ManagedObject
+@Description("File Cache Statistics")
+public class FileCacheStatsProviderGlobal extends FileCacheStatsProvider {
+
+ public FileCacheStatsProviderGlobal(String name) {
+ super(name);
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countHitEvent")
+ public void countHitEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ hitsCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countMissEvent")
+ public void countMissEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ missesCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countInfoHitEvent")
+ public void countInfoHitEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ infoHitsCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countInfoMissEvent")
+ public void countInfoMissEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ infoMissesCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countContentHitEvent")
+ public void countContentHitEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ contentHitsCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:countContentMissEvent")
+ public void countContentMissEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ contentMissesCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:incOpenCacheEntriesEvent")
+ public void incOpenCacheEntriesEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ openCacheEntriesCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:decOpenCacheEntriesEvent")
+ public void decOpenCacheEntriesEvent(@ProbeParam("fileCacheName") String fileCacheName) {
+ openCacheEntriesCount.decrement();
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:addHeapSizeEvent")
+ public void addHeapSizeEvent(@ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {
+ final long newSize = heapSize.addAndGet(size);
+ for(;;) {
+ final long maxSize = maxHeapSize.get();
+ if (newSize > maxSize) {
+ if (maxHeapSize.compareAndSet(maxSize, newSize)) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:subHeapSizeEvent")
+ public void subHeapSizeEvent(@ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {
+ heapSize.addAndGet(-size);
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:addMappedMemorySizeEvent")
+ public void addMappedMemorySizeEvent(
+ @ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {
+ final long newSize = mappedMemorySize.addAndGet(size);
+ for(;;) {
+ final long maxMemSize = maxMappedMemorySize.get();
+ if (newSize > maxMemSize) {
+ if (maxMappedMemorySize.compareAndSet(maxMemSize, newSize)) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:file-cache:subMappedMemorySizeEvent")
+ public void subMappedMemorySizeEvent(
+ @ProbeParam("fileCacheName") String fileCacheName,
+ @ProbeParam("size") long size) {
+ mappedMemorySize.addAndGet(-size);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/KeepAliveStatsProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/KeepAliveStatsProvider.java
new file mode 100644
index 0000000..b24c90a
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/KeepAliveStatsProvider.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+import org.glassfish.external.probe.provider.annotations.ProbeListener;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.external.statistics.CountStatistic;
+import org.glassfish.external.statistics.annotations.Reset;
+import org.glassfish.external.statistics.impl.CountStatisticImpl;
+import org.glassfish.gmbal.AMXMetadata;
+import org.glassfish.gmbal.Description;
+import org.glassfish.gmbal.ManagedAttribute;
+import org.glassfish.gmbal.ManagedObject;
+import org.glassfish.grizzly.http.KeepAlive;
+
+/**
+ * Keep-alive statistics
+ *
+ * @author Alexey Stashok
+ */
+@AMXMetadata(type = "keep-alive-mon", group = "monitoring")
+@ManagedObject
+@Description("Keep-Alive Statistics")
+public class KeepAliveStatsProvider implements StatsProvider {
+
+ private final String name;
+ protected final CountStatisticImpl maxRequestsCount = new CountStatisticImpl("MaxRequests", "count", "Maximum number of requests allowed on a single keep-alive connection");
+ protected final CountStatisticImpl timeoutInSeconds = new CountStatisticImpl("SecondsTimeouts", "seconds", "Keep-alive timeout value in seconds");
+ protected final CountStatisticImpl totalKeepAliveConnectionsCount = new CountStatisticImpl("TotalCountConnections", "count", "Total number of keep-alive connections that were accepted");
+ protected final CountStatisticImpl keepAliveConnectionsCount = new CountStatisticImpl("CountConnections", "count", "Number of connections in keep-alive mode");
+ protected final CountStatisticImpl hitsCount = new CountStatisticImpl("CountHits", "count", "Number of requests received by connections in keep-alive mode");
+ protected final CountStatisticImpl refusalsCount = new CountStatisticImpl("CountRefusals", "count", "Number of keep-alive connections that were rejected");
+ protected final CountStatisticImpl timeoutsCount = new CountStatisticImpl("CountTimeouts", "count", "Number of keep-alive connections that timed out");
+ protected volatile KeepAlive keepAliveStats;
+
+ public KeepAliveStatsProvider(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public Object getStatsObject() {
+ return keepAliveStats;
+ }
+
+ @Override
+ public void setStatsObject(Object object) {
+ if (object instanceof KeepAlive) {
+ keepAliveStats = (KeepAlive) object;
+ } else {
+ keepAliveStats = null;
+ }
+ }
+
+ @ManagedAttribute(id = "maxrequests")
+ @Description("Maximum number of requests allowed on a single keep-alive connection")
+ public CountStatistic getMaxKeepAliveRequestsCount() {
+ return maxRequestsCount;
+ }
+
+ @ManagedAttribute(id = "secondstimeouts")
+ @Description("Keep-alive timeout value in seconds")
+ public CountStatistic getKeepAliveTimeoutInSeconds() {
+ return timeoutInSeconds;
+ }
+
+ @ManagedAttribute(id = "countconnections")
+ @Description("Number of connections in keep-alive mode")
+ public CountStatistic getKeepAliveConnectionsCount() {
+ return keepAliveConnectionsCount;
+ }
+
+ @ManagedAttribute(id = "countflushes")
+ @Description("Number of keep-alive connections that were closed")
+ public CountStatistic getFlushesCount() {
+ final CountStatisticImpl stats = new CountStatisticImpl(
+ "CountFlushes",
+ "count",
+ "Number of keep-alive connections that were closed"
+ );
+ stats.setCount(Math.max(0, totalKeepAliveConnectionsCount.getCount() - timeoutsCount.getCount()));
+
+ return stats;
+ }
+
+ @ManagedAttribute(id = "counthits")
+ @Description("Number of requests received by connections in keep-alive mode")
+ public CountStatistic getHitsCount() {
+ return hitsCount;
+ }
+
+ @ManagedAttribute(id = "countrefusals")
+ @Description("Number of keep-alive connections that were rejected")
+ public CountStatistic getRefusalsCount() {
+ return refusalsCount;
+ }
+
+ @ManagedAttribute(id = "counttimeouts")
+ @Description("Number of keep-alive connections that timed out")
+ public CountStatistic getTimeoutsCount() {
+ return timeoutsCount;
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:setMaxCountRequestsEvent")
+ public void setMaxCountRequestsEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("maxRequests") int max) {
+ if (name.equals(listenerName)) {
+ maxRequestsCount.setCount(max);
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:setTimeoutInSecondsEvent")
+ public void setTimeoutInSecondsEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("timeoutInSeconds") int timeoutInSeconds) {
+ if (name.equals(listenerName)) {
+ this.timeoutInSeconds.setCount(timeoutInSeconds);
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountConnectionsEvent")
+ public void incrementCountConnectionsEvent(@ProbeParam("listenerName") String listenerName) {
+ if (name.equals(listenerName)) {
+ keepAliveConnectionsCount.increment();
+ totalKeepAliveConnectionsCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:decrementCountConnectionsEvent")
+ public void decrementCountConnectionsEvent(@ProbeParam("listenerName") String listenerName) {
+ if (name.equals(listenerName)) {
+ keepAliveConnectionsCount.decrement();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountFlushesEvent")
+ public void incrementCountFlushesEvent(@ProbeParam("listenerName") String listenerName) {
+// if (name.equals(listenerName)) {
+// flushesCount.increment();
+// }
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountHitsEvent")
+ public void incrementCountHitsEvent(@ProbeParam("listenerName") String listenerName) {
+ if (name.equals(listenerName)) {
+ hitsCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountRefusalsEvent")
+ public void incrementCountRefusalsEvent(@ProbeParam("listenerName") String listenerName) {
+ if (name.equals(listenerName)) {
+ refusalsCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountTimeoutsEvent")
+ public void incrementCountTimeoutsEvent(@ProbeParam("listenerName") String listenerName) {
+ if (name.equals(listenerName)) {
+ timeoutsCount.increment();
+ }
+ }
+
+ @Reset
+ public void reset() {
+ if (keepAliveStats != null) {
+ maxRequestsCount.setCount(keepAliveStats.getMaxRequestsCount());
+ timeoutInSeconds.setCount(keepAliveStats.getIdleTimeoutInSeconds());
+ }
+
+ keepAliveConnectionsCount.setCount(0);
+ totalKeepAliveConnectionsCount.setCount(0);
+ hitsCount.setCount(0);
+ refusalsCount.setCount(0);
+ timeoutsCount.setCount(0);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/KeepAliveStatsProviderGlobal.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/KeepAliveStatsProviderGlobal.java
new file mode 100644
index 0000000..a48188e
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/KeepAliveStatsProviderGlobal.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+import org.glassfish.external.probe.provider.annotations.ProbeListener;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.gmbal.AMXMetadata;
+import org.glassfish.gmbal.Description;
+import org.glassfish.gmbal.ManagedObject;
+
+/**
+ * Server wide Keep-alive statistics
+ *
+ * @author Amy Roh
+ */
+@AMXMetadata(type = "keep-alive-mon", group = "monitoring")
+@ManagedObject
+@Description("Keep-Alive Statistics")
+public class KeepAliveStatsProviderGlobal extends KeepAliveStatsProvider {
+
+ public KeepAliveStatsProviderGlobal(String name) {
+ super(name);
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:setMaxCountRequestsEvent")
+ @Override
+ public void setMaxCountRequestsEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("maxRequests") int max) {
+ maxRequestsCount.setCount(max);
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:setTimeoutInSecondsEvent")
+ @Override
+ public void setTimeoutInSecondsEvent(
+ @ProbeParam("listenerName") String listenerName,
+ @ProbeParam("timeoutInSeconds") int timeoutInSeconds) {
+ this.timeoutInSeconds.setCount(timeoutInSeconds);
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountConnectionsEvent")
+ @Override
+ public void incrementCountConnectionsEvent(@ProbeParam("listenerName") String listenerName) {
+ keepAliveConnectionsCount.increment();
+ totalKeepAliveConnectionsCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:decrementCountConnectionsEvent")
+ @Override
+ public void decrementCountConnectionsEvent(@ProbeParam("listenerName") String listenerName) {
+ keepAliveConnectionsCount.decrement();
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountFlushesEvent")
+ @Override
+ public void incrementCountFlushesEvent(@ProbeParam("listenerName") String listenerName) {
+// flushesCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountHitsEvent")
+ @Override
+ public void incrementCountHitsEvent(@ProbeParam("listenerName") String listenerName) {
+ hitsCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountRefusalsEvent")
+ @Override
+ public void incrementCountRefusalsEvent(@ProbeParam("listenerName") String listenerName) {
+ refusalsCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:connections-keep-alive:incrementCountTimeoutsEvent")
+ @Override
+ public void incrementCountTimeoutsEvent(@ProbeParam("listenerName") String listenerName) {
+ timeoutsCount.increment();
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/StatsProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/StatsProvider.java
new file mode 100644
index 0000000..dc62886
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/StatsProvider.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+/**
+ * General <tt>StatsProvider</tt> interface.
+ *
+ * @author Alexey Stashok
+ */
+public interface StatsProvider {
+ /**
+ * Get object, from which <tt>StatsProvider</tt> can get statistics directly
+ * without listening emitting events.
+ *
+ * @return statistics
+ */
+ public Object getStatsObject();
+
+ /**
+ * Set object, from which <tt>StatsProvider</tt> can get statistics directly
+ * without listening emitting events.
+ *
+ * @param object statistics
+ */
+ public void setStatsObject(Object object);
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProvider.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProvider.java
new file mode 100644
index 0000000..7b05cb5
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProvider.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+import org.glassfish.external.probe.provider.annotations.ProbeListener;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.external.statistics.CountStatistic;
+import org.glassfish.external.statistics.annotations.Reset;
+import org.glassfish.external.statistics.impl.CountStatisticImpl;
+import org.glassfish.gmbal.AMXMetadata;
+import org.glassfish.gmbal.Description;
+import org.glassfish.gmbal.ManagedAttribute;
+import org.glassfish.gmbal.ManagedObject;
+import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
+
+/**
+ * Thread Pool statistics
+ *
+ * @author Alexey Stashok
+ */
+@AMXMetadata(type = "thread-pool-mon", group = "monitoring")
+@ManagedObject
+@Description("Thread Pool Statistics")
+public class ThreadPoolStatsProvider implements StatsProvider {
+
+ private final String name;
+ protected final CountStatisticImpl maxThreadsCount = new CountStatisticImpl("MaxThreads", "count", "Maximum number of threads allowed in the thread pool");
+ protected final CountStatisticImpl coreThreadsCount = new CountStatisticImpl("CoreThreads", "count", "Core number of threads in the thread pool");
+
+ protected final CountStatisticImpl totalExecutedTasksCount = new CountStatisticImpl("TotalExecutedTasksCount", "count", "Provides the total number of tasks, which were executed by the thread pool");
+ protected final CountStatisticImpl currentThreadCount = new CountStatisticImpl("CurrentThreadCount", "count", "Provides the number of request processing threads currently in the listener thread pool");
+ protected final CountStatisticImpl currentThreadsBusy = new CountStatisticImpl("CurrentThreadsBusy", "count", "Provides the number of request processing threads currently in use in the listener thread pool serving requests");
+
+ protected volatile ThreadPoolConfig threadPoolConfig;
+
+ public ThreadPoolStatsProvider(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public Object getStatsObject() {
+ return threadPoolConfig;
+ }
+
+ @Override
+ public void setStatsObject(Object object) {
+ if (object instanceof ThreadPoolConfig) {
+ threadPoolConfig = (ThreadPoolConfig) object;
+ } else {
+ threadPoolConfig = null;
+ }
+ }
+
+ @ManagedAttribute(id = "maxthreads")
+ @Description("Maximum number of threads allowed in the thread pool")
+ public CountStatistic getMaxThreadsCount() {
+ return maxThreadsCount;
+ }
+
+ @ManagedAttribute(id = "corethreads")
+ @Description("Core number of threads in the thread pool")
+ public CountStatistic getCoreThreadsCount() {
+ return coreThreadsCount;
+ }
+
+ @ManagedAttribute(id = "totalexecutedtasks")
+ @Description("Provides the total number of tasks, which were executed by the thread pool")
+ public CountStatistic getTotalExecutedTasksCount() {
+ return totalExecutedTasksCount;
+ }
+
+ @ManagedAttribute(id = "currentthreadcount")
+ @Description("Provides the number of request processing threads currently in the listener thread pool")
+ public CountStatistic getCurrentThreadCount() {
+ return currentThreadCount;
+ }
+
+ @ManagedAttribute(id = "currentthreadsbusy")
+ @Description("Provides the number of request processing threads currently in use in the listener thread pool serving requests.")
+ public CountStatistic getCurrentThreadsBusy() {
+ return currentThreadsBusy;
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:setMaxThreadsEvent")
+ public void setMaxThreadsEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("maxNumberOfThreads") int maxNumberOfThreads) {
+
+ if (name.equals(monitoringId)) {
+ maxThreadsCount.setCount(maxNumberOfThreads);
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:setCoreThreadsEvent")
+ public void setCoreThreadsEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("coreNumberOfThreads") int coreNumberOfThreads) {
+
+ if (name.equals(monitoringId)) {
+ coreThreadsCount.setCount(coreNumberOfThreads);
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:threadAllocatedEvent")
+ public void threadAllocatedEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {
+
+ if (name.equals(monitoringId)) {
+ currentThreadCount.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:threadReleasedEvent")
+ public void threadReleasedEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {
+
+ if (name.equals(monitoringId)) {
+ currentThreadCount.decrement();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:threadDispatchedFromPoolEvent")
+ public void threadDispatchedFromPoolEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {
+
+ if (name.equals(monitoringId)) {
+ currentThreadsBusy.increment();
+ }
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:threadReturnedToPoolEvent")
+ public void threadReturnedToPoolEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {
+
+ if (name.equals(monitoringId)) {
+ totalExecutedTasksCount.increment();
+ currentThreadsBusy.decrement();
+ }
+ }
+
+ @Reset
+ public void reset() {
+ if (threadPoolConfig != null) {
+ maxThreadsCount.setCount(threadPoolConfig.getMaxPoolSize());
+ coreThreadsCount.setCount(threadPoolConfig.getCorePoolSize());
+ currentThreadCount.setCount(0);
+ currentThreadsBusy.setCount(0);
+ }
+
+ totalExecutedTasksCount.setCount(0);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProviderGlobal.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProviderGlobal.java
new file mode 100644
index 0000000..16bf7ae
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/monitor/stats/ThreadPoolStatsProviderGlobal.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.services.impl.monitor.stats;
+
+import org.glassfish.external.probe.provider.annotations.ProbeListener;
+import org.glassfish.external.probe.provider.annotations.ProbeParam;
+import org.glassfish.gmbal.AMXMetadata;
+import org.glassfish.gmbal.Description;
+import org.glassfish.gmbal.ManagedObject;
+
+/**
+ * Server wide Thread Pool statistics
+ *
+ * @author Amy Roh
+ */
+@AMXMetadata(type = "thread-pool-mon", group = "monitoring")
+@ManagedObject
+@Description("Thread Pool Statistics")
+public class ThreadPoolStatsProviderGlobal extends ThreadPoolStatsProvider {
+
+ public ThreadPoolStatsProviderGlobal(String name) {
+ super(name);
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:setMaxThreadsEvent")
+ public void setMaxThreadsEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("maxNumberOfThreads") int maxNumberOfThreads) {
+
+ maxThreadsCount.setCount(maxNumberOfThreads);
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:setCoreThreadsEvent")
+ public void setCoreThreadsEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("coreNumberOfThreads") int coreNumberOfThreads) {
+
+ coreThreadsCount.setCount(coreNumberOfThreads);
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:threadAllocatedEvent")
+ public void threadAllocatedEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {
+
+ currentThreadCount.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:threadReleasedEvent")
+ public void threadReleasedEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {
+
+ currentThreadCount.decrement();
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:threadDispatchedFromPoolEvent")
+ public void threadDispatchedFromPoolEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {
+
+ currentThreadsBusy.increment();
+ }
+
+ @ProbeListener("glassfish:kernel:thread-pool:threadReturnedToPoolEvent")
+ public void threadReturnedToPoolEvent(
+ @ProbeParam("monitoringId") String monitoringId,
+ @ProbeParam("threadPoolName") String threadPoolName,
+ @ProbeParam("threadId") long threadId) {
+
+ totalExecutedTasksCount.increment();
+ currentThreadsBusy.decrement();
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/FileMonitoringImpl.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/FileMonitoringImpl.java
new file mode 100644
index 0000000..ea6a1ff
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/FileMonitoringImpl.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel;
+
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.api.admin.FileMonitoring;
+
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Jerome Dochez
+ */
+@Service
+public class FileMonitoringImpl implements FileMonitoring, PostConstruct {
+
+ @Inject
+ ExecutorService executor;
+
+ @Inject
+ ScheduledExecutorService scheduledExecutor;
+
+ @Inject
+ Events events;
+
+ final Map<File, List<FileChangeListener>> listeners = new HashMap<File, List<FileChangeListener>>();
+ final Map<File, Long> monitored = new HashMap<File, Long>();
+
+ public void postConstruct() {
+ final ScheduledFuture<?> future = scheduledExecutor.scheduleWithFixedDelay(new Runnable() {
+ public void run() {
+ if (monitored.isEmpty()) {
+ return;
+ }
+ // check our list of monitored files for any changes
+ Set<File> monitoredFiles = new HashSet<File>();
+ monitoredFiles.addAll(listeners.keySet());
+ for (File file : monitoredFiles) {
+ if (!file.exists()) {
+ removed(file);
+ listeners.remove(file);
+ monitored.remove(file);
+ } else
+ if (file.lastModified()!=monitored.get(file)) {
+ // file has changed
+ monitored.put(file, file.lastModified());
+ changed(file);
+ }
+ }
+
+ }
+ }, 0, 500, TimeUnit.MILLISECONDS);
+ events.register(new org.glassfish.api.event.EventListener() {
+ @Override
+ public void event(Event event) {
+ if (event.is(EventTypes.PREPARE_SHUTDOWN)) {
+ System.out.println("FileMonitoring shutdown");
+ future.cancel(false);
+ }
+ }
+ });
+ }
+
+ public synchronized void monitors(File file, FileChangeListener listener) {
+
+ if (monitored.containsKey(file)) {
+ listeners.get(file).add(listener);
+ } else {
+ List<FileChangeListener> list = new ArrayList<FileChangeListener>();
+ list.add(listener);
+ listeners.put(file, list);
+ monitored.put(file, file.lastModified());
+ }
+ }
+
+ public synchronized void fileModified(File file) {
+ monitored.put(file, 0L);
+ }
+
+ private void removed(final File file) {
+ for (final FileChangeListener listener : listeners.get(file)) {
+ executor.submit(new Runnable() {
+ public void run() {
+ listener.deleted(file);
+ }
+ });
+ }
+
+ }
+
+ private void changed(final File file) {
+ for (final FileChangeListener listener : listeners.get(file)) {
+ executor.submit(new Runnable() {
+ public void run() {
+ listener.changed(file);
+ }
+ });
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/KernelLoggerInfo.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/KernelLoggerInfo.java
new file mode 100644
index 0000000..66c14a1
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/KernelLoggerInfo.java
@@ -0,0 +1,626 @@
+/*
+ * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel;
+
+import java.util.logging.Logger;
+import org.glassfish.logging.annotation.LogMessageInfo;
+import org.glassfish.logging.annotation.LogMessagesResourceBundle;
+import org.glassfish.logging.annotation.LoggerInfo;
+
+/**
+ * Logger information for the internal-api module.
+ * @author Tom Mueller
+ */
+/* Module private */
+public class KernelLoggerInfo {
+ private static final String LOGMSG_PREFIX = "NCLS-CORE";
+
+ @LogMessagesResourceBundle
+ private static final String SHARED_LOGMESSAGE_RESOURCE = "org.glassfish.kernel.LogMessages";
+
+ @LoggerInfo(subsystem = "CORE", description = "Core Kernel", publish = true)
+ private static final String CORE_LOGGER = "javax.enterprise.system.core";
+ private static final Logger coreLogger = Logger.getLogger(
+ CORE_LOGGER, SHARED_LOGMESSAGE_RESOURCE);
+
+ public static Logger getLogger() {
+ return coreLogger;
+ }
+
+ @LogMessageInfo(
+ message = "Cannot decode parameter {0} = {1}",
+ level = "WARNING")
+ public static final String cantDecodeParameter = LOGMSG_PREFIX + "-00001";
+
+ @LogMessageInfo(
+ message = "Cannot instantiate model for command {0}",
+ cause = "The service that implements the command could not be loaded.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String cantInstantiateCommand = LOGMSG_PREFIX + "-00002";
+
+ @LogMessageInfo(
+ message = "Exception while running a command",
+ cause = "An unexpected exception occurred while running a command.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String invocationException = LOGMSG_PREFIX + "-00003";
+
+ @LogMessageInfo(
+ message = "Unable to get an instance of ClusterExecutor; Cannot dynamically reconfigure instances",
+ level = "WARNING")
+ public static final String cantGetClusterExecutor = LOGMSG_PREFIX + "-00004";
+
+ @LogMessageInfo(
+ message = "Can't delete local password file: {0}",
+ level = "WARNING")
+ public static final String cantDeletePasswordFile = LOGMSG_PREFIX + "-00005";
+
+ @LogMessageInfo(
+ message = "Can't create local password file: {0}",
+ level = "WARNING")
+ public static final String cantCreatePasswordFile = LOGMSG_PREFIX + "-00006";
+
+ @LogMessageInfo(
+ message = "Timeout occurred when processing Admin Console request.",
+ cause = "A request for a lock timed out while processing an admin console request.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String consoleRequestTimeout = LOGMSG_PREFIX + "-00007";
+
+ @LogMessageInfo(
+ message = "Cannot process admin console request.",
+ cause = "InterruptedException occurred while the service thread is running.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String consoleCannotProcess = LOGMSG_PREFIX + "-00008";
+
+ @LogMessageInfo(
+ message = "Unable to serve resource: {0}. Cause: {1}",
+ cause = "An I/O error occurred while serving a resource request.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String consoleResourceError = LOGMSG_PREFIX + "-00009";
+
+ @LogMessageInfo(
+ message = "Resource not found: {0}",
+ level = "WARNING")
+ public static final String consoleResourceNotFound = LOGMSG_PREFIX + "-00010";
+
+ @LogMessageInfo(
+ message = "Console cannot be initialized due to an exception.",
+ level = "INFO")
+ public static final String consoleCannotInitialize = LOGMSG_PREFIX + "-00011";
+
+ @LogMessageInfo(
+ message = "Cannot write property ''{0} = {1}'' for AdminService in domain.xml, exception: {2}",
+ level = "INFO")
+ public static final String consoleCannotWriteProperty = LOGMSG_PREFIX + "-00012";
+
+ @LogMessageInfo(
+ message = "Shutdown procedure finished",
+ level = "INFO")
+ public static final String shutdownFinished = LOGMSG_PREFIX + "-00013";
+
+ @LogMessageInfo(
+ message = "Shutdown required",
+ cause = "An unexpected exception occurred while changing run levels. A shutdown is required.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String shutdownRequired = LOGMSG_PREFIX + "-00014";
+
+ @LogMessageInfo(
+ message = "Shutdown requested",
+ level = "INFO")
+ public static final String shutdownRequested = LOGMSG_PREFIX + "-00015";
+
+ @LogMessageInfo(
+ message = "Startup service failed to start",
+ cause = "An unexpected exception occurred while starting the startup service. A shutdown is required.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String startupFailure = LOGMSG_PREFIX + "-00016";
+
+ @LogMessageInfo(
+ message = "{0} ({1}) startup time : {2} ({3}ms), startup services({4}ms), total({5}ms)",
+ level = "INFO")
+ public static final String startupEndMessage = LOGMSG_PREFIX + "-00017";
+
+ @LogMessageInfo(
+ message = "TOTAL TIME INCLUDING CLI: {0}",
+ level = "INFO")
+ public static final String startupTotalTime = LOGMSG_PREFIX + "-00018";
+
+ @LogMessageInfo(
+ message = "Shutting down server due to startup exception",
+ cause = "An unexpected exception occurred while starting the server. A shutdown is required.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String startupFatalException = LOGMSG_PREFIX + "-00019";
+
+ @LogMessageInfo(
+ message = "Timed out, ignoring some startup service status",
+ level = "WARNING")
+ public static final String startupWaitTimeout = LOGMSG_PREFIX + "-00020";
+
+ @LogMessageInfo(
+ message = "Unexpected exception during startup",
+ cause = "An unexpected exception occurred while starting the server.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String startupException = LOGMSG_PREFIX + "-00021";
+
+ @LogMessageInfo(
+ message = "Loading application {0} done in {1} ms",
+ level = "INFO")
+ public static final String loadingApplicationTime = LOGMSG_PREFIX + "-00022";
+
+ @LogMessageInfo(
+ message = "Enable of application {0} completed with a warning: {1}",
+ level = "INFO")
+ public static final String loadingApplicationWarning = LOGMSG_PREFIX + "-00023";
+
+ @LogMessageInfo(
+ message = "Error during enabling",
+ cause = "An unexpected exception occurred while enabling an application.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String loadingApplicationErrorEnable = LOGMSG_PREFIX + "-00024";
+
+ @LogMessageInfo(
+ message = "Error during disabling",
+ cause = "An unexpected exception occurred while disabling an application.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String loadingApplicationErrorDisable = LOGMSG_PREFIX + "-00025";
+
+ @LogMessageInfo(
+ message = "Exception during lifecycle processing",
+ cause = "An unexpected exception occurred during lifecycle processing.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String lifecycleException = LOGMSG_PREFIX + "-00026";
+
+ @LogMessageInfo(
+ message = "ApplicationMetaDataProvider {0} requires {1} but no other ApplicationMetaDataProvider provides it",
+ level = "WARNING")
+ public static final String applicationMetaDataProvider = LOGMSG_PREFIX + "-00027";
+
+ @LogMessageInfo(
+ message = "Inconsistent state - nothing is providing {0} yet it passed validation",
+ cause = "An unexpected condition during lifecycle processing.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String inconsistentLifecycleState = LOGMSG_PREFIX + "-00028";
+
+ @LogMessageInfo(
+ message = "Cannot start container {0}, exception: {1}",
+ cause = "An unexpected condition during lifecycle processing.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String cantStartContainer = LOGMSG_PREFIX + "-00029";
+
+ @LogMessageInfo(
+ message = "Cannot release container {0}, exception {1}",
+ level = "INFO")
+ public static final String cantReleaseContainer = LOGMSG_PREFIX + "-00030";
+
+ @LogMessageInfo(
+ message = "Error while closing deployable artifact {0}, exception: {1}",
+ cause = "An unexpected exception occurred during lifecycle processing.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String errorClosingArtifact = LOGMSG_PREFIX + "-00031";
+
+ @LogMessageInfo(
+ message = "Error while expanding archive file",
+ cause = "An unexpected exception occurred during lifecycle processing.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String errorExpandingFile = LOGMSG_PREFIX + "-00032";
+
+ @LogMessageInfo(
+ message = "Cannot find sniffer for module type: {0}",
+ cause = "An unexpected condition occurred during lifecycle processing.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String cantFindSniffer = LOGMSG_PREFIX + "-00033";
+
+ @LogMessageInfo(
+ message = "Cannot find any sniffer for deployed app: {0}",
+ cause = "An unexpected condition occurred during lifecycle processing.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String cantFindSnifferForApp = LOGMSG_PREFIX + "-00034";
+
+ @LogMessageInfo(
+ message = "Exception occurred while satisfying optional package dependencies",
+ level = "INFO")
+ public static final String exceptionOptionalDepend = LOGMSG_PREFIX + "-00035";
+
+ @LogMessageInfo(
+ message = "Cannot delete created temporary file {0}",
+ level = "WARNING")
+ public static final String cantDeleteTempFile = LOGMSG_PREFIX + "-00036";
+
+ @LogMessageInfo(
+ message = "Source is not a directory, using temporary location {0} ",
+ level = "WARNING")
+ public static final String sourceNotDirectory = LOGMSG_PREFIX + "-00037";
+
+ @LogMessageInfo(
+ message = "Cannot find the application type for the artifact at: {0}. Was the container or sniffer removed?",
+ cause = "An unexpected condition occurred while loading an application.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String cantFindApplicationInfo = LOGMSG_PREFIX + "-00038";
+
+ @LogMessageInfo(
+ message = "Exception during application deployment",
+ cause = "An unexpected exception occurred while deploying an application.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String deployException = LOGMSG_PREFIX + "-00039";
+
+ @LogMessageInfo(
+ message = "Cannot determine original location for application: {0}",
+ cause = "A URL syntax error occurred.",
+ action = "Check the application for proper syntax.",
+ level = "SEVERE")
+ public static final String cantDetermineLocation = LOGMSG_PREFIX + "-00040";
+
+ @LogMessageInfo(
+ message = "Application deployment failed: {0}",
+ cause = "The deployment command for an application failed as indicated in the message.",
+ action = "Check the application and redeploy.",
+ level = "SEVERE")
+ public static final String deployFail = LOGMSG_PREFIX + "-00041";
+
+ @LogMessageInfo(
+ message = "IOException while opening deployed artifact",
+ cause = "An unexpected exception occurred while deploying an application.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionOpenArtifact = LOGMSG_PREFIX + "-00042";
+
+ @LogMessageInfo(
+ message = "Application previously deployed is not at its original location any more: {0}",
+ cause = "An unexpected exception occurred while loading an application.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String notFoundInOriginalLocation = LOGMSG_PREFIX + "-00043";
+
+ @LogMessageInfo(
+ message = "System property called {0} is null, is this intended?",
+ level = "WARNING")
+ public static final String systemPropertyNull = LOGMSG_PREFIX + "-00044";
+
+ @LogMessageInfo(
+ message = "Invalid classpath entry for common class loader ignored: {0}, exception: {1}",
+ level = "WARNING")
+ public static final String invalidClassPathEntry = LOGMSG_PREFIX + "-00045";
+
+ @LogMessageInfo(
+ message = "Cannot find javadb client jar file, derby jdbc driver will not be available by default.",
+ level = "INFO")
+ public static final String cantFindDerby = LOGMSG_PREFIX + "-00046";
+
+ @LogMessageInfo(
+ message = "CommonClassLoaderServiceImpl is unable to process {0} because of an exception: {1}",
+ level = "INFO")
+ public static final String exceptionProcessingJAR = LOGMSG_PREFIX + "-00047";
+
+ @LogMessageInfo(
+ message = "Invalid InputStream returned for {0}",
+ cause = "Unable to retrieve an entry from the archive.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String invalidInputStream = LOGMSG_PREFIX + "-00048";
+
+ @LogMessageInfo(
+ message = "Exception while processing {0} inside {1} of size {2}, exception: {3}",
+ cause = "An unexpected exception occurred while processing an archive.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionWhileParsing = LOGMSG_PREFIX + "-00049";
+
+ @LogMessageInfo(
+ message = "Cannot open sub-archive {0} from {1}",
+ cause = "An unexpected exception occurred while processing an archive.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String cantOpenSubArchive = LOGMSG_PREFIX + "-00050";
+
+ @LogMessageInfo(
+ message = "Cannot close sub archive {0}, exception: {1}",
+ cause = "An unexpected exception occurred while closing an archive.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionWhileClosing = LOGMSG_PREFIX + "-00051";
+
+ @LogMessageInfo(
+ message = "Exception loading lifecycle module [{0}]; [{1}]",
+ cause = "An unexpected exception occurred while loading a lifecycle module.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionLoadingLifecycleModule = LOGMSG_PREFIX + "-00052";
+
+ @LogMessageInfo(
+ message = "Lifecycle module [{0}] threw ServerLifecycleException, exception: {1}",
+ level = "WARNING")
+ public static final String serverLifecycleException = LOGMSG_PREFIX + "-00053";
+
+ @LogMessageInfo(
+ message = "Lifecycle module [{0}] threw an Exception; please check your lifecycle module. Exception: {1}",
+ level = "WARNING")
+ public static final String lifecycleModuleException = LOGMSG_PREFIX + "-00054";
+
+ @LogMessageInfo(
+ message = "GrizzlyService stop-proxy problem",
+ level = "WARNING")
+ public static final String grizzlyStopProxy = LOGMSG_PREFIX + "-00055";
+
+ @LogMessageInfo(
+ message = "Unable to start the server. Closing all ports",
+ cause = "An unexpected exception occurred while starting the grizzly service.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String grizzlyCantStart = LOGMSG_PREFIX + "-00056";
+
+ @LogMessageInfo(
+ message = "Exception closing port: {0}, exception: {1}",
+ cause = "An unexpected exception occurred while closing a port.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String grizzlyCloseException = LOGMSG_PREFIX + "-00057";
+
+ @LogMessageInfo(
+ message = "Network listener {0} on port {1} disabled per domain.xml",
+ level = "INFO")
+ public static final String grizzlyPortDisabled = LOGMSG_PREFIX + "-00058";
+
+ @LogMessageInfo(
+ message = "GrizzlyService endpoint registration problem",
+ level = "WARNING")
+ public static final String grizzlyEndpointRegistration = LOGMSG_PREFIX + "-00059";
+
+ @LogMessageInfo(
+ message = "Skip registering endpoint with non existent virtual server: {0}",
+ level = "WARNING")
+ public static final String grizzlyNonExistentVS = LOGMSG_PREFIX + "-00060";
+
+ @LogMessageInfo(
+ message = "Attempting to start the {0} container.",
+ level = "INFO")
+ public static final String snifferAdapterStartingContainer = LOGMSG_PREFIX + "-00061";
+
+ @LogMessageInfo(
+ message = "Done with starting {0} container in {1} ms.",
+ level = "INFO")
+ public static final String snifferAdapterContainerStarted = LOGMSG_PREFIX + "-00062";
+
+ @LogMessageInfo(
+ message = "Could not start container, no exception provided.",
+ cause = "The container could not be started.",
+ action = "Ensure the libraries for the container are available.",
+ level = "SEVERE")
+ public static final String snifferAdapterNoContainer = LOGMSG_PREFIX + "-00063";
+
+ @LogMessageInfo(
+ message = "Exception while starting container {0}, exception: {1}",
+ cause = "An exception occurred while attempting to start the container.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String snifferAdapterExceptionStarting = LOGMSG_PREFIX + "-00064";
+
+ @LogMessageInfo(
+ message = "Exception while mapping the request.",
+ cause = "An exception occurred while mapping a request to the container.",
+ action = "Please resolve issues mentioned in the stack trace.",
+ level = "SEVERE")
+ public static final String snifferAdapterExceptionMapping = LOGMSG_PREFIX + "-00065";
+
+ @LogMessageInfo(
+ message = "Cannot add new configuration to the Config element",
+ cause = "An exception occurred while adding the container configuration to the domain.xml.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionAddContainer = LOGMSG_PREFIX + "-00066";
+
+ @LogMessageInfo(
+ message = "Exception while enabling or disabling the autodeployment of applications",
+ cause = "An exception occurred while enabling or disabling the autodeployment of applications.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionAutodeployment = LOGMSG_PREFIX + "-00067";
+
+ @LogMessageInfo(
+ message = "Exception while sending an event.",
+ cause = "An exception occurred while sending an event.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionSendEvent = LOGMSG_PREFIX + "-00068";
+
+ @LogMessageInfo(
+ message = "Exception while dispatching an event",
+ level = "WARNING")
+ public static final String exceptionDispatchEvent = LOGMSG_PREFIX + "-00069";
+
+ @LogMessageInfo(
+ message = "An exception occurred while stopping the server, continuing.",
+ cause = "An exception occurred while stopping the server.",
+ action = "Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionDuringShutdown = LOGMSG_PREFIX + "-00070";
+
+ @LogMessageInfo(
+ message = "The ManagedJobConfig bean {0} was changed by {1}",
+ level = "FINE")
+ public static final String changeManagedJobConfig = LOGMSG_PREFIX + "-00071";
+
+ @LogMessageInfo(
+ message = "Cleaning Job {0}",
+ level = "FINE")
+ public static final String cleaningJob = LOGMSG_PREFIX + "-00072";
+
+ @LogMessageInfo(
+ message = "Initializing Job Cleanup service",
+ level = "FINE")
+ public static final String initializingJobCleanup = LOGMSG_PREFIX + "-00073";
+
+ @LogMessageInfo(
+ message = "Initializing Managed Config bean",
+ level = "FINE")
+ public static final String initializingManagedConfigBean = LOGMSG_PREFIX + "-00074";
+
+ @LogMessageInfo(
+ message = "Scheduling Cleanup",
+ level = "FINE")
+ public static final String schedulingCleanup = LOGMSG_PREFIX + "-00075";
+
+ @LogMessageInfo(
+ message = "Exception when cleaning jobs caused",
+ cause="An exception occured when cleaning the managed jobs",
+ action="Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionCleaningJobs = LOGMSG_PREFIX + "-00076";
+
+ @LogMessageInfo(
+ message = "-passwordfile specified, but the actual file was not, ignoring ...",
+ cause="A software error is causing an incorrect argument sequence.",
+ action="No action necessary.",
+ level = "WARNING")
+ public static final String optionButNoArg = LOGMSG_PREFIX + "-00077";
+
+ @LogMessageInfo(
+ message = "Invalid context root for the admin console application, using default: {0}",
+ level = "INFO")
+ public static final String invalidContextRoot = LOGMSG_PREFIX + "-00078";
+
+ @LogMessageInfo(
+ message = "Admin Console Adapter: context root: {0}",
+ level = "INFO")
+ public static final String contextRoot = LOGMSG_PREFIX + "-00079";
+
+ @LogMessageInfo(
+ message = "Failed to configure the ManagedJobConfig bean",
+ cause="While running the configure-managed-jobs command, a write transaction to the ManagedJobConfig bean failed.",
+ action="Check the system logs and contact Oracle support.",
+ level = "WARNING")
+ public static final String configFailManagedJobConfig = LOGMSG_PREFIX + "-00080";
+
+ @LogMessageInfo(
+ message = "Unable to get the ManagedJobConfig bean.",
+ cause="While running the configure-managed-jobs command, access to the ManagedJobConfig bean failed.",
+ action="Check the system logs and contact Oracle support.",
+ level = "WARNING")
+ public static final String getFailManagedJobConfig = LOGMSG_PREFIX + "-00081";
+
+ @LogMessageInfo(
+ message = "Exiting after upgrade",
+ level = "INFO")
+ public static final String exitUpgrade = LOGMSG_PREFIX + "-00082";
+
+ @LogMessageInfo(
+ message = "Exception while attempting to shutdown after upgrade",
+ cause="An exception occured when shutting down the server after an upgrade.",
+ action="Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionUpgrade = LOGMSG_PREFIX + "-00083";
+
+ @LogMessageInfo(
+ message = "Cannot find port information from domain.xml",
+ cause="No port value is available in the NetworkListener config bean",
+ action="Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String noPort = LOGMSG_PREFIX + "-00084";
+
+ @LogMessageInfo(
+ message = "Cannot parse port value: {0}, using port 8080",
+ cause="There is an invalid port value in the domain.xml file.",
+ action="Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String badPort = LOGMSG_PREFIX + "-00085";
+
+ @LogMessageInfo(
+ message = "Unknown address {0}",
+ cause="There is an invalid address value in the domain.xml file.",
+ action="Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String badAddress = LOGMSG_PREFIX + "-00086";
+
+ @LogMessageInfo(
+ message = "Grizzly Framework {0} started in: {1}ms - bound to [{2}]",
+ level = "INFO")
+ public static final String grizzlyStarted = LOGMSG_PREFIX + "-00087";
+
+ @LogMessageInfo(
+ message = "Exception during postConstruct of DynamicReloadService",
+ cause="An unexpected exception occured.",
+ action="Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionDRS = LOGMSG_PREFIX + "-00088";
+
+ @LogMessageInfo(
+ message = "Cannot determine host name, will use localhost exclusively",
+ cause="An unexpected exception occured.",
+ action="Check the system logs and contact Oracle support.",
+ level = "SEVERE")
+ public static final String exceptionHostname = LOGMSG_PREFIX + "-00089";
+
+ @LogMessageInfo(
+ message = "Internal Server error: {0}",
+ cause="An unexpected exception occured.",
+ action="Check the system logs and contact Oracle support.",
+ level = "WARNING")
+ public static final String exceptionMapper = LOGMSG_PREFIX + "-00090";
+
+ @LogMessageInfo(
+ message = "Unable to set customized error page",
+ cause="An unexpected exception occured.",
+ action="Check the system logs and contact Oracle support.",
+ level = "WARNING")
+ public static final String exceptionMapper2 = LOGMSG_PREFIX + "-00091";
+
+ @LogMessageInfo(
+ message = "Server shutdown initiated",
+ level = "INFO")
+ public static final String serverShutdownInit = LOGMSG_PREFIX + "-00092";
+
+ @LogMessageInfo(
+ message = "Problem while attempting to install admin console!",
+ level = "INFO")
+ public static final String adminGuiInstallProblem = LOGMSG_PREFIX + "-00093";
+
+ @LogMessageInfo(
+ message = "Unable to load checkpoint",
+ cause="An unexpected exception occured.",
+ action="Check the system logs and contact Oracle support.",
+ level = "WARNING")
+ public static final String exceptionLoadCheckpoint = LOGMSG_PREFIX + "-00094";
+
+ @LogMessageInfo(
+ message = "Resuming command {0} from its last checkpoint.",
+ level = "INFO")
+ public static final String checkpointAutoResumeStart = LOGMSG_PREFIX + "-00095";
+
+ @LogMessageInfo(
+ message = "Automatically resumed command {0} finished with exit code {1}. \nMessage: {2}",
+ level = "INFO")
+ public static final String checkpointAutoResumeDone = LOGMSG_PREFIX + "-00096";
+
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/admin/.gitkeep_empty_dir b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/admin/.gitkeep_empty_dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/admin/.gitkeep_empty_dir
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/bean_validator/BeanValidatorNamingProxy.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/bean_validator/BeanValidatorNamingProxy.java
new file mode 100644
index 0000000..1b4c855
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/bean_validator/BeanValidatorNamingProxy.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.bean_validator;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.naming.NamingException;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorContext;
+import javax.validation.ValidatorFactory;
+
+import org.glassfish.api.naming.NamespacePrefixes;
+import org.glassfish.api.naming.NamedNamingObjectProxy;
+import org.jvnet.hk2.annotations.Optional;
+import org.jvnet.hk2.annotations.Service;
+
+@Service
+@NamespacePrefixes({BeanValidatorNamingProxy.nameForValidator, BeanValidatorNamingProxy.nameForValidatorFactory})
+public class BeanValidatorNamingProxy implements NamedNamingObjectProxy {
+
+ static final String nameForValidator = "java:comp/Validator";
+ static final String nameForValidatorFactory = "java:comp/ValidatorFactory";
+
+ private ValidatorFactory validatorFactory;
+ private Validator validator;
+
+ @Inject @Named("ValidationNamingProxy") @Optional
+ private NamedNamingObjectProxy cdiNamingProxy;
+
+ public Object handle(String name) throws NamingException {
+ Object result = null;
+
+ // see if CDI is active, use BeanManager to obtain Validator/ValidatorFactory
+ if (cdiNamingProxy != null) {
+ result = cdiNamingProxy.handle(name);
+
+ if (result != null) {
+ return result;
+ }
+ }
+
+ if (nameForValidator.equals(name)) {
+ result = getValidator();
+ } else if (nameForValidatorFactory.equals(name)) {
+ result = getValidatorFactory();
+ }
+ return result;
+ }
+
+ private Validator getValidator() throws NamingException {
+ if (null == validator) {
+ try {
+ ValidatorFactory factory = getValidatorFactory();
+ ValidatorContext validatorContext = factory.usingContext();
+ validator = validatorContext.getValidator();
+ } catch (Throwable t) {
+ NamingException ne = new NamingException("Error retrieving Validator for " + nameForValidator + " lookup");
+ ne.initCause(t);
+ throw ne;
+ }
+ }
+ return validator;
+ }
+
+ private ValidatorFactory getValidatorFactory() throws NamingException {
+
+ if (null == validatorFactory) {
+ try {
+ validatorFactory = Validation.buildDefaultValidatorFactory();
+ } catch (Throwable t) {
+ NamingException ne = new NamingException("Error retrieving ValidatorFactory for " + nameForValidatorFactory + " lookup");
+ ne.initCause(t);
+ throw ne;
+ }
+ }
+
+ return validatorFactory;
+ }
+
+
+
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/config/DefaultConfigParser.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/config/DefaultConfigParser.java
new file mode 100644
index 0000000..99a36a6
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/config/DefaultConfigParser.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.config;
+
+import com.sun.enterprise.config.serverbeans.Config;
+import java.beans.PropertyVetoException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.xml.stream.XMLStreamReader;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.admin.config.ConfigParser;
+import org.glassfish.api.admin.config.Container;
+import org.glassfish.config.support.GlassFishConfigBean;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+import org.jvnet.hk2.config.ConfigModel;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.Dom;
+import org.jvnet.hk2.config.DomDocument;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+
+/**
+ * @author Jerome Dochez
+ * @author Vivek Pandey
+ */
+@Service
+public class DefaultConfigParser implements ConfigParser {
+
+ @Inject @Named( ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ Config config;
+
+ Logger logger = KernelLoggerInfo.getLogger();
+
+ @Override
+ public <T extends Container> T parseContainerConfig(ServiceLocator habitat, final URL configuration, Class<T> configType) throws IOException {
+ // I don't use the GlassFish document here as I don't need persistence
+ final DomDocument doc = new DomDocument<GlassFishConfigBean>(habitat) {
+ @Override
+ public Dom make(final ServiceLocator habitat, XMLStreamReader xmlStreamReader, GlassFishConfigBean dom, ConfigModel configModel) {
+ // by default, people get the translated view.
+ return new GlassFishConfigBean(habitat,this, dom, configModel, xmlStreamReader);
+ }
+ };
+
+ // add the new container configuration to the server config
+ final T container = doc.getRoot().createProxy(configType);
+
+ try {
+ ConfigSupport.apply(new SingleConfigCode<Config>() {
+ @Override
+ public Object run(Config config) throws PropertyVetoException, TransactionFailure {
+ config.getContainers().add(container);
+ return null;
+ }
+ }, config);
+ } catch(TransactionFailure e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionAddContainer, e);
+ }
+
+ return container;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedAdminCtrImpl.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedAdminCtrImpl.java
new file mode 100644
index 0000000..eb6d9b0
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedAdminCtrImpl.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.embedded;
+
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+import org.glassfish.internal.embedded.LifecycleException;
+import org.glassfish.internal.embedded.Port;
+import org.glassfish.internal.embedded.admin.CommandExecution;
+import org.glassfish.internal.embedded.admin.CommandParameters;
+import org.glassfish.internal.embedded.admin.EmbeddedAdminContainer;
+import org.glassfish.api.container.Sniffer;
+import org.glassfish.api.admin.CommandRunner;
+import org.glassfish.api.admin.ParameterMap;
+import org.glassfish.api.ActionReport;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Properties;
+
+import com.sun.enterprise.v3.common.PlainTextActionReporter;
+import org.glassfish.internal.api.InternalSystemAdministrator;
+
+/**
+ * Implementation of the embedded command execution
+ *
+ * @author Jerome Dochez
+ */
+@Service
+public class EmbeddedAdminCtrImpl implements EmbeddedAdminContainer {
+
+ @Inject
+ CommandRunner runner;
+
+ @Inject
+ private InternalSystemAdministrator kernelIdentity;
+
+ private final static List<Sniffer> empty = new ArrayList<Sniffer>();
+
+ public List<Sniffer> getSniffers() {
+ return empty;
+ }
+
+ public void bind(Port port, String protocol) {
+
+ }
+
+ public void start() throws LifecycleException {
+
+ }
+
+ public void stop() throws LifecycleException {
+
+ }
+
+ public CommandExecution execute(String commandName, CommandParameters params) {
+ ParameterMap props = params.getOptions();
+ if (params.getOperands().size() > 0) {
+ for (String op : params.getOperands())
+ props.add("DEFAULT", op);
+ }
+ final ActionReport report = new PlainTextActionReporter();
+ CommandExecution ce = new CommandExecution() {
+
+ public ActionReport getActionReport() {
+ return report;
+ }
+
+ public ActionReport.ExitCode getExitCode() {
+ return report.getActionExitCode();
+ }
+
+ public String getMessage() {
+ return report.getMessage();
+ }
+ };
+ runner.getCommandInvocation(commandName, report, kernelIdentity.getSubject()).parameters(props).execute();
+ return ce;
+ }
+
+ public void bind(Port port) {
+
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedDeployerImpl.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedDeployerImpl.java
new file mode 100644
index 0000000..db7818a
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedDeployerImpl.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.embedded;
+
+import com.sun.enterprise.config.serverbeans.*;
+import com.sun.enterprise.deploy.shared.ArchiveFactory;
+import com.sun.enterprise.util.io.FileUtils;
+import com.sun.enterprise.v3.common.PlainTextActionReporter;
+import java.beans.PropertyVetoException;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.CommandRunner;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.deployment.DeployCommandParameters;
+import org.glassfish.api.deployment.UndeployCommandParameters;
+import org.glassfish.api.deployment.archive.*;
+import org.glassfish.deployment.common.*;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.data.*;
+import org.glassfish.internal.deployment.Deployment;
+import org.glassfish.internal.deployment.ExtendedDeploymentContext;
+import org.glassfish.internal.deployment.SnifferManager;
+import org.glassfish.internal.embedded.*;
+import org.glassfish.internal.embedded.Server;
+import org.glassfish.kernel.KernelLoggerInfo;
+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 Jerome Dochez
+ */
+@Service
+public class EmbeddedDeployerImpl implements EmbeddedDeployer {
+
+ @Inject
+ Deployment deployment;
+
+ @Inject
+ Server server;
+
+ @Inject
+ CommandRunner commandRunner;
+
+ @Inject
+ ServiceLocator habitat;
+
+ @Inject
+ ArchiveFactory factory;
+
+ @Inject
+ SnifferManager snifferMgr;
+
+ @Inject
+ ServerEnvironment env;
+
+ @Inject
+ DasConfig config;
+
+ Map<String, EmbeddedDeployedInfo> deployedApps = new HashMap<String, EmbeddedDeployedInfo>();
+
+ final static Logger logger = KernelLoggerInfo.getLogger();
+
+ @Override
+ public File getApplicationsDir() {
+ return env.getApplicationRepositoryPath();
+ }
+
+ @Override
+ public File getAutoDeployDir() {
+ return new File(env.getDomainRoot(), config.getAutodeployDir());
+ }
+
+ @Override
+ public void setAutoDeploy(final boolean flag) {
+
+ String value = config.getAutodeployEnabled();
+ boolean active = value!=null && Boolean.parseBoolean(
+ config.getAutodeployEnabled());
+ if (active!=flag) {
+ try {
+ ConfigSupport.apply(new SingleConfigCode<DasConfig>() {
+ @Override
+ public Object run(DasConfig dasConfig) throws PropertyVetoException, TransactionFailure {
+ dasConfig.setAutodeployEnabled(Boolean.valueOf(flag).toString());
+ return null;
+ }
+ }, config);
+ } catch(TransactionFailure e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionAutodeployment, e);
+ }
+ }
+ }
+
+ @Override
+ public String deploy(File archive, DeployCommandParameters params) {
+ try {
+ ReadableArchive r = factory.openArchive(archive);
+ return deploy(r, params);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.deployException, e);
+ }
+
+ return null;
+ }
+
+ @Override
+ public String deploy(ReadableArchive archive, DeployCommandParameters params) {
+
+ // ensure server is started. start it if not started.
+ try {
+ server.start();
+ } catch (LifecycleException e) {
+ throw new RuntimeException(e);
+ }
+
+ ActionReport report = new PlainTextActionReporter();
+ if (params==null) {
+ params = new DeployCommandParameters();
+ }
+ ExtendedDeploymentContext initialContext = new DeploymentContextImpl(report, archive, params, env);
+ ArchiveHandler archiveHandler = null;
+ try {
+ archiveHandler = deployment.getArchiveHandler(archive);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ if (archiveHandler==null) {
+ throw new RuntimeException("Cannot find archive handler for source archive");
+ }
+ if (params.name==null) {
+ params.name = archiveHandler.getDefaultApplicationName(archive, initialContext);
+ }
+ ExtendedDeploymentContext context = null;
+ try {
+ context = deployment.getBuilder(logger, params, report).source(archive).archiveHandler(archiveHandler).build(initialContext);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ if(params.property != null){
+ context.getAppProps().putAll(params.property);
+ }
+
+ if(params.properties != null){
+ context.getAppProps().putAll(params.properties);
+ }
+
+ ApplicationInfo appInfo = null;
+ try {
+ appInfo = deployment.deploy(context);
+ } catch(Exception e) {
+ logger.log(Level.SEVERE, KernelLoggerInfo.deployException, e);
+ }
+ if (appInfo!=null) {
+ boolean isDirectory = new File(archive.getURI().getPath()).isDirectory();
+ EmbeddedDeployedInfo info = new EmbeddedDeployedInfo(appInfo, context.getModulePropsMap(), context.getAppProps(),
+ isDirectory);
+ deployedApps.put(appInfo.getName(), info);
+ return appInfo.getName();
+ }
+ return null;
+ }
+
+ @Override
+ public void undeploy(String name, UndeployCommandParameters params) {
+
+ ActionReport report = habitat.getService(ActionReport.class, "plain");
+ EmbeddedDeployedInfo info = deployedApps.get(name);
+ ApplicationInfo appInfo = info!=null?info.appInfo:null;
+ if (appInfo==null) {
+ appInfo = deployment.get(name);
+ }
+ if (appInfo == null) {
+ report.setMessage(
+ "Cannot find deployed application of name " + name);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+
+ ReadableArchive source = appInfo.getSource();
+ if (source == null) {
+ report.setMessage(
+ "Cannot get source archive for undeployment");
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+
+ if (params==null) {
+ params = new UndeployCommandParameters(name);
+ }
+ params.origin = UndeployCommandParameters.Origin.undeploy;
+
+ ExtendedDeploymentContext deploymentContext;
+ try {
+ deploymentContext = deployment.getBuilder(logger, params, report).source(source).build();
+
+ if (info!=null) {
+ for (ModuleInfo module : appInfo.getModuleInfos()) {
+ info.map.put(module.getName(), module.getModuleProps());
+ deploymentContext.getModuleProps().putAll(module.getModuleProps());
+ }
+ deploymentContext.setModulePropsMap(info.map);
+ deploymentContext.getAppProps().putAll(info.appProps);
+ }
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Cannot create context for undeployment ", e);
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ return;
+ }
+
+
+ deployment.undeploy(name, deploymentContext);
+
+
+ if (report.getActionExitCode().equals(ActionReport.ExitCode.SUCCESS)) {
+ if (params.keepreposdir == null) {
+ params.keepreposdir = false;
+ }
+ if ( !params.keepreposdir && info != null && !info.isDirectory && source.exists()) {
+ FileUtils.whack(new File(source.getURI()));
+ }
+ //remove context from generated
+ deploymentContext.clean();
+
+ }
+
+ }
+
+ @Override
+ public void undeployAll() {
+ for (String appName : deployedApps.keySet()) {
+ undeploy(appName, null);
+ }
+
+ }
+
+ private final static class EmbeddedDeployedInfo {
+ final ApplicationInfo appInfo;
+ final Map<String, Properties> map;
+ final boolean isDirectory;
+ Properties appProps;
+
+
+ public EmbeddedDeployedInfo(ApplicationInfo appInfo, Map<String, Properties> map, Properties appProps,
+ boolean isDirectory) {
+ this.appInfo = appInfo;
+ this.map = map;
+ this.appProps = appProps;
+ this.isDirectory = isDirectory;
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedDomainPersistence.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedDomainPersistence.java
new file mode 100644
index 0000000..83784df
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedDomainPersistence.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.embedded;
+
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.util.LocalStringManagerImpl;
+import com.sun.enterprise.v3.server.DomainXmlPersistence;
+import javax.inject.Inject;
+import org.jvnet.hk2.config.DomDocument;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.logging.Level;
+
+/**
+ * Configuration file persistence handler for embedded
+ *
+ * @author Jerome Dochez
+ * @author bhavanishankar@dev.java.net
+ */
+public class EmbeddedDomainPersistence extends DomainXmlPersistence {
+
+ @Inject
+ StartupContext startupContext;
+
+ final static LocalStringManagerImpl localStrings =
+ new LocalStringManagerImpl(DomainXmlPersistence.class);
+
+ /**
+ * Returns the destination file for saving the embedded configuration file,
+ * when set.
+ *
+ * @return the embedded configuration file if set in read-write mode.
+ * @throws IOException
+ */
+ @Override
+ protected File getDestination() throws IOException {
+ String configFileReadOnly = startupContext.getArguments().getProperty(
+ "org.glassfish.embeddable.configFileReadOnly");
+ if (configFileReadOnly != null &&
+ !Boolean.valueOf(configFileReadOnly).booleanValue()) {
+ try {
+ URI uri = EmbeddedDomainXml.getDomainXml(startupContext).toURI();
+ if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return new File(uri);
+ } else {
+ // TODO :: localize the message.
+ throw new IOException("configurationFile is writable but is not a file");
+ }
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+ }
+ return null; // Don't persist domain.xml anywhere.
+ }
+
+ @Override
+ public void save(DomDocument doc) throws IOException {
+ File destination = getDestination();
+ if (destination == null) {
+ String msg = localStrings.getLocalString("NoLocation",
+ "domain.xml cannot be persisted, null destination");
+ logger.finer(msg);
+ return;
+ }
+ super.save(doc);
+ }
+
+ @Override
+ protected void saved(File destination) {
+ logger.log(Level.INFO, "Configuration saved at {0}", destination);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedDomainXml.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedDomainXml.java
new file mode 100644
index 0000000..01066d8
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedDomainXml.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.embedded;
+
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.v3.server.GFDomainXml;
+import org.glassfish.server.ServerEnvironmentImpl;
+import javax.inject.Inject;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+
+/**
+ * Embedded domain.xml, can use externally pointed domain.xml
+ *
+ * @author Jerome Dochez
+ * @author bhavanishankar@dev.java.net
+ */
+public class EmbeddedDomainXml extends GFDomainXml {
+
+ @Inject
+ StartupContext startupContext;
+
+ @Override
+ protected URL getDomainXml(ServerEnvironmentImpl env) throws IOException {
+ return getDomainXml(startupContext);
+ }
+
+ static URL getDomainXml(StartupContext startupContext) throws IOException {
+ String configFileURI = startupContext.getArguments().getProperty(
+ "org.glassfish.embeddable.configFileURI");
+ if (configFileURI != null) { // user specified domain.xml
+ return URI.create(configFileURI).toURL();
+ }
+ String instanceRoot = startupContext.getArguments().getProperty(
+ "com.sun.aas.instanceRoot");
+ File domainXml = new File(instanceRoot, "config/domain.xml");
+ if (domainXml.exists()) { // domain/config/domain.xml, if exists.
+ return domainXml.toURI().toURL();
+ }
+ return EmbeddedDomainXml.class.getClassLoader().getResource(
+ "org/glassfish/embed/domain.xml");
+ }
+
+ @Override
+ protected void upgrade() {
+ // for now, we don't upgrade in embedded mode...
+ }
+
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedInhabitantsParser.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedInhabitantsParser.java
new file mode 100644
index 0000000..85dc2b0
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/EmbeddedInhabitantsParser.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.embedded;
+
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.bootstrap.PopulatorPostProcessor;
+import org.glassfish.hk2.utilities.DescriptorImpl;
+
+import com.sun.enterprise.server.logging.LogManagerService;
+import com.sun.enterprise.v3.admin.PrivateAdminAdapter;
+import com.sun.enterprise.v3.admin.PublicAdminAdapter;
+import com.sun.enterprise.v3.admin.adapter.AdminConsoleAdapter;
+import com.sun.enterprise.v3.server.DomainXmlPersistence;
+import com.sun.enterprise.v3.server.GFDomainXml;
+
+import javax.inject.Inject;
+
+/**
+ * Kernel's decoration for embedded environment.
+ *
+ * @author Jerome Dochez
+ */
+public class EmbeddedInhabitantsParser implements PopulatorPostProcessor {
+
+ @Inject
+ private ServiceLocator serviceLocator;
+
+ public EmbeddedInhabitantsParser() {
+ }
+
+ public String getName() {
+ return "Embedded";
+ }
+
+// private void decorate(InhabitantsParser parser) {
+//
+// // we don't want to reconfigure the loggers.
+//
+// parser.drop(AdminConsoleAdapter.class);
+//
+// String enableCLI = System.getenv("GF_EMBEDDED_ENABLE_CLI");
+// if (enableCLI == null || !enableCLI.equalsIgnoreCase("true")) {
+// parser.drop(PublicAdminAdapter.class);
+// parser.drop(LogManagerService.class);
+// parser.drop(PrivateAdminAdapter.class);
+// }
+// parser.replace(GFDomainXml.class, EmbeddedDomainXml.class);
+//
+// parser.replace(DomainXmlPersistence.class, EmbeddedDomainPersistence.class);
+//
+// }
+
+ @Override
+ public DescriptorImpl process(ServiceLocator serviceLocator, DescriptorImpl descriptorImpl) {
+
+ // we don't want to reconfigure the loggers.
+
+ boolean skip = false;
+
+ if (AdminConsoleAdapter.class.getCanonicalName().equals(
+ descriptorImpl.getImplementation())) {
+ skip = true;
+ }
+
+ String enableCLI = System.getenv("GF_EMBEDDED_ENABLE_CLI");
+ if (enableCLI == null || !enableCLI.equalsIgnoreCase("true")) {
+
+ if (PublicAdminAdapter.class.getCanonicalName().equals(
+ descriptorImpl.getImplementation())
+ || LogManagerService.class.getCanonicalName().equals(
+ descriptorImpl.getImplementation())
+ || PrivateAdminAdapter.class.getCanonicalName().equals(
+ descriptorImpl.getImplementation())) {
+ skip = true;
+ }
+ }
+
+ if (GFDomainXml.class.getCanonicalName().equals(
+ descriptorImpl.getImplementation())) {
+ descriptorImpl.setImplementation(EmbeddedDomainXml.class
+ .getCanonicalName());
+ }
+
+ if (DomainXmlPersistence.class.getCanonicalName().equals(
+ descriptorImpl.getImplementation())) {
+ descriptorImpl.setImplementation(EmbeddedDomainPersistence.class
+ .getCanonicalName());
+ }
+
+ if (!skip) {
+ return descriptorImpl;
+ }
+ return null;
+ }
+}
+
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/PortImpl.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/PortImpl.java
new file mode 100644
index 0000000..c6a86b1
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/PortImpl.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.embedded;
+
+import java.beans.PropertyVetoException;
+import java.util.List;
+
+import com.sun.enterprise.config.serverbeans.HttpService;
+import com.sun.enterprise.config.serverbeans.VirtualServer;
+import org.glassfish.grizzly.config.dom.Http;
+import org.glassfish.grizzly.config.dom.NetworkConfig;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.grizzly.config.dom.NetworkListeners;
+import org.glassfish.grizzly.config.dom.Protocol;
+import org.glassfish.grizzly.config.dom.Protocols;
+import org.glassfish.grizzly.config.dom.ThreadPool;
+import org.glassfish.grizzly.config.dom.Transport;
+import org.glassfish.grizzly.config.dom.Transports;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.CommandRunner;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.internal.embedded.Port;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.hk2.api.PerLookup;
+import org.jvnet.hk2.config.*;
+
+/**
+ * Abstract to port creation and destruction
+ */
+@Service
+@PerLookup
+public class PortImpl implements Port {
+ @Inject
+ CommandRunner runner = null;
+ @Inject @Named("plain")
+ ActionReport report = null;
+ @Inject
+ PortsImpl ports;
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ NetworkConfig config;
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ HttpService httpService;
+ String listenerName;
+ int number;
+ String defaultVirtualServer = "server";
+
+ public void setPortNumber(final int portNumber) {
+ number = portNumber;
+ }
+
+ public void close() {
+ removeListener();
+ ports.remove(this);
+ }
+
+ private void removeListener() {
+ try {
+ ConfigSupport.apply(new ConfigCode() {
+ public Object run(ConfigBeanProxy[] params) throws PropertyVetoException, TransactionFailure {
+ final NetworkListeners nt = (NetworkListeners) params[0];
+ final VirtualServer vs = (VirtualServer) params[1];
+ final Protocols protocols = (Protocols) params[2];
+ List<Protocol> protos = protocols.getProtocol();
+ for (Protocol proto : protos) {
+ if (proto.getName().equals(listenerName)) {
+ protos.remove(proto);
+ break;
+ }
+ }
+ final List<NetworkListener> list = nt.getNetworkListener();
+ for (NetworkListener listener : list) {
+ if (listener.getName().equals(listenerName)) {
+ list.remove(listener);
+ break;
+ }
+ }
+ String regex = listenerName + ",?";
+ String lss = vs.getNetworkListeners();
+ if (lss != null) {
+ vs.setNetworkListeners(lss.replaceAll(regex, ""));
+ }
+ return null;
+ }
+ }, config.getNetworkListeners(),
+ httpService.getVirtualServerByName(defaultVirtualServer),
+ config.getProtocols());
+ } catch (TransactionFailure tf) {
+ tf.printStackTrace();
+ throw new RuntimeException(tf);
+ }
+ }
+
+ public int getPortNumber() {
+ return number;
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/PortsImpl.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/PortsImpl.java
new file mode 100644
index 0000000..8f6c9a3
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/embedded/PortsImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.embedded;
+
+import org.jvnet.hk2.annotations.Service;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.internal.embedded.Port;
+import org.glassfish.internal.embedded.Ports;
+
+import java.io.IOException;
+import java.util.*;
+import org.glassfish.api.admin.ServerEnvironment;
+
+import org.glassfish.grizzly.config.dom.NetworkConfig;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+
+/**
+ * @author Jerome Dochez
+ */
+@Service
+public class PortsImpl implements Ports {
+
+
+ @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
+ NetworkConfig network;
+
+ @Inject
+ ServiceLocator habitat;
+
+ final Map<Integer, Port> ports = new HashMap<Integer, Port>();
+
+ public Port createPort(int number) throws IOException {
+ return createPort(Integer.valueOf(number));
+ }
+
+ private Port createPort(Integer portNumber) throws IOException {
+
+ for (NetworkListener nl : network.getNetworkListeners().getNetworkListener()) {
+ if (nl.getPort().equals(portNumber.toString())) {
+ throw new IOException("Port " + portNumber + " is already configured");
+ }
+ }
+ for (Integer pn : ports.keySet()) {
+ if (pn.equals(portNumber)) {
+ throw new IOException("Port " + portNumber + " is alredy open");
+ }
+ }
+ PortImpl port = habitat.getService(PortImpl.class);
+ port.setPortNumber(portNumber);
+ ports.put(portNumber, port);
+ return port; }
+
+ public Collection<Port> getPorts() {
+ return ports.values();
+ }
+
+ public void remove(Port port) {
+ ports.remove(port.getPortNumber());
+ }
+}
diff --git a/nucleus/core/kernel/src/main/java/org/glassfish/kernel/event/EventsImpl.java b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/event/EventsImpl.java
new file mode 100644
index 0000000..beebef1
--- /dev/null
+++ b/nucleus/core/kernel/src/main/java/org/glassfish/kernel/event/EventsImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.kernel.event;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventListener.Event;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.event.Events;
+import org.glassfish.api.event.RestrictTo;
+import org.glassfish.deployment.common.DeploymentException;
+import org.glassfish.kernel.KernelLoggerInfo;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Simple implementation of the events dispatching facility.
+ *
+ * @author Jerome Dochez
+ */
+@Service
+public class EventsImpl implements Events {
+
+ @Inject
+ ExecutorService executor;
+
+ final static Logger logger = KernelLoggerInfo.getLogger();
+
+ List<EventListener> listeners = Collections.synchronizedList(new ArrayList<EventListener>());
+
+ @Override
+ public synchronized void register(EventListener listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void send(final Event event) {
+ send(event, true);
+ }
+
+ @Override
+ public void send(final Event event, boolean asynchronously) {
+
+ List<EventListener> l = new ArrayList<EventListener>();
+ l.addAll(listeners);
+ for (final EventListener listener : l) {
+
+ Method m =null;
+ try {
+ // check if the listener is interested with his event.
+ m = listener.getClass().getMethod("event", Event.class);
+ } catch (Throwable ex) {
+ // We need to catch Throwable, otherwise we can server not to
+ // shutdown when the following happens:
+ // Assume a bundle which has registered a event listener
+ // has been uninstalled without unregistering the listener.
+ // listener.getClass() refers to a class of such an uninstalled
+ // bundle. If framework has been refreshed, then the
+ // classloader can't be used further to load any classes.
+ // As a result, an exception like NoClassDefFoundError is thrown
+ // from getMethod.
+ logger.log(Level.SEVERE, KernelLoggerInfo.exceptionSendEvent, ex);
+ }
+ if (m!=null) {
+ RestrictTo fooBar = m.getParameterTypes()[0].getAnnotation(RestrictTo.class);
+ if (fooBar!=null) {
+ EventTypes interested = EventTypes.create(fooBar.value());
+ if (!event.is(interested)) {
+ continue;
+ }
+ }
+ }
+
+ if (asynchronously) {
+ executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ listener.event(event);
+ } catch(Throwable e) {
+ logger.log(Level.WARNING, KernelLoggerInfo.exceptionDispatchEvent, e);
+ }
+ }
+ });
+ } else {
+ try {
+ listener.event(event);
+ } catch (DeploymentException de) {
+ // when synchronous listener throws DeploymentException
+ // we re-throw the exception to abort the deployment
+ throw de;
+ } catch (Throwable e) {
+ logger.log(Level.WARNING, KernelLoggerInfo.exceptionDispatchEvent, e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public synchronized boolean unregister(EventListener listener) {
+ return listeners.remove(listener);
+ }
+}
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/attach.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/attach.1
new file mode 100644
index 0000000..1d78c6d
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/attach.1
@@ -0,0 +1,55 @@
+attach(1) asadmin Utility Subcommands attach(1)
+
+NAME
+ attach - attaches to subcommands that were started using asadmin
+ --detach or that contain progress information
+
+SYNOPSIS
+ attach [--help]
+ job_id
+
+DESCRIPTION
+ The attach subcommand attaches to subcommands that were started using
+ the asadmin utility option --detach or that contain progress
+ information. The --detach option detaches long-running subcommands and
+ executes them in the background in detach mode.
+
+ Job IDs are assigned to the subcommands (jobs), and can be used to view
+ the status of a job and its output. Use the list-jobs(1) subcommand to
+ view the jobs and their job IDs, and the configure-managed-jobs(1)
+ subcommand to configure how long information about the jobs is kept.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+OPERANDS
+ job_id
+ The ID of the job for which you want to view status and output.
+
+EXAMPLES
+ Example 1, Attaching to a Subcommand and Checking Its Status
+ This example attaches to the deploy subcommand with a job ID of 20
+ and shows that the job is finished. If a subcommand is still in
+ progress, the output displays the current status, for example, 64%:
+ Uploading bits.
+
+ asadmin> attach 20
+ Finished execution of deploy
+ Command attach executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ list-jobs(1), configure-managed-jobs(1)
+
+ asadmin(1M)
+
+Java EE 8 12 Jan 2013 attach(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/configure-managed-jobs.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/configure-managed-jobs.1
new file mode 100644
index 0000000..15a2138
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/configure-managed-jobs.1
@@ -0,0 +1,66 @@
+configure-managed-jobs(1) asadmin Utility Subcommands configure-managed-jobs(1)
+
+NAME
+ configure-managed-jobs - configures how long information about
+ subcommands that were started using asadmin --detach or that contain
+ progress information is kept
+
+SYNOPSIS
+ configure-managed-jobs [--help]
+ [--in-memory-retention-period in-memory-retention-period]
+ [--job-retention-period job-retention-period]
+ [--cleanup-initial-delay cleanup-initial-delay]
+ [--cleanup-poll-interval cleanup-poll-interval]
+
+DESCRIPTION
+ The configure-managed-jobs subcommand configures how long information
+ about subcommands (jobs) that were started using the asadmin utility
+ option --detach or that contain progress information is kept. The
+ --detach option detaches long-running subcommands and executes them in
+ the background in detach mode. Job information includes subcommand
+ progress and status.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ in-memory-retention-period
+ Specifies how long a completed job is kept in memory after the job
+ is finished. The default value is 1 hour.
+
+ --job-retention-period
+ Specifies how long a job is stored. The default value is 24 hours.
+
+ --cleanup-initial-delay
+ After server startup, specifies the initial delay after which the
+ cleanup service starts purging jobs. The default value is 5
+ minutes.
+
+ --cleanup-poll-interval
+ Specifies the time interval after which the cleanup service polls
+ for expired jobs. The default value is 20 minutes.
+
+EXAMPLES
+ Example 1, Configuring the Job Retention Period
+ This example sets the job retention period to 36 hours. Time
+ periods can be specified in Hh|Mm|Ss for hours, minutes, or
+ seconds.
+
+ asadmin> configure-managed-jobs --job-retention-period=36h
+ Command configure-managed-jobs executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ list-jobs(1)
+
+ asadmin(1M)
+
+Java EE 8 09 Aug 2017 configure-managed-jobs(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/create-jvm-options.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/create-jvm-options.1
new file mode 100644
index 0000000..2151889
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/create-jvm-options.1
@@ -0,0 +1,212 @@
+create-jvm-options(1) asadmin Utility Subcommands create-jvm-options(1)
+
+NAME
+ create-jvm-options - creates options for the Java application launcher
+
+SYNOPSIS
+ create-jvm-options [--help] [--target target] [--profiler={true|false}]
+ (jvm-option-name=jvm-option-value) [:jvm-option-name=jvm-option-value*]
+
+DESCRIPTION
+ The create-jvm-options subcommand creates command-line options that are
+ passed to the Java application launcher when GlassFish Server is
+ started. The options that this subcommand creates are in addition to
+ the options that are preset with GlassFish Server. Java application
+ launcher options are stored in the Java configuration java—config
+ element or the profiler profiler element of the domain.xml file. The
+ options are sent to the command line in the order they appear in the
+ java—config element or the profiler profiler element in the domain.xml
+ file.
+
+ Profiler options are used to record the settings that are required to
+ start a particular profiler. The profiler must already exist. If
+ necessary, use the create-profiler(1) subcommand to create the
+ profiler.
+
+ This subcommand can be used to create the following types of options:
+
+ * Java system properties. These options are set through the -D
+ option of the Java application launcher. For example:
+
+ -Djava.security.manager
+
+ -Denvironment=Production
+
+ * Startup parameters for the Java application launcher. These
+ options are preceded by the dash character (-). For example:
+
+ --XX:PermSize=size
+
+ -Xmx1024m
+
+ -d64
+
+ If the subcommand specifies an option that already exists, the command
+ does not re-create the option.
+
+ Note
+ +----------------------------------------+
+ | Ensure that any option that |
+ | you create is valid. The |
+ | subcommand might allow you |
+ | to create an invalid option, |
+ | but such an invalid option |
+ | can cause startup to fail. |
+ +----------------------------------------+
+
+ An option can be verified by examining the server log after GlassFish
+ Server starts. Options for the Java application launcher are written to
+ the server.log file before any other information when GlassFish Server
+ starts.
+
+ The addition of some options requires a server restart for changes to
+ become effective. Other options are set immediately in the environment
+ of the domain administration server (DAS) and do not require a restart.
+ Whether a restart is required depends on the type of option.
+
+ * Restart is not required for Java system properties whose names do
+ not start with -Djava. or -Djavax. (including the trailing
+ period). For example, restart is not required for the following
+ Java system property:
+
+ -Denvironment=Production
+
+ * Restart is required for the following options:
+
+ * Java system properties whose names start with -Djava. or
+ -Djavax. (including the trailing period). For example:
+
+ -Djava.security.manager
+
+ * Startup parameters for the Java application launcher. For
+ example:
+
+ -client
+
+ -Xmx1024m
+
+ -d64
+
+ To restart the DAS, use the restart-domain(1) command.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ Specifies the target on which you are creating Java application
+ launcher options.
+
+ Valid values are as follows:
+
+ server
+ Specifies the DAS (default).
+
+ instance-name
+ Specifies a GlassFish Server instance.
+
+ cluster-name
+ Specifies a cluster.
+
+ configuration-name
+ Specifies a named configuration.
+
+ --profiler
+ Indicates whether the Java application launcher options are for the
+ profiler. The profiler must exist for this option to be true.
+ Default is false.
+
+OPERANDS
+ jvm-option-name
+ One or more options delimited by a colon (:). The format of an
+ option depends on the following:
+
+ * If the option has a name and a value, the format is
+ option-name=value.
+
+ * If the option has only a name, the format is option-name. For
+ example, -Xmx2048m.
+
+ * If the first option name could be misinterpreted as one or more
+ asadmin short options, the format is -- option-name. For
+ example, -server in the following command could be
+ misinterpreted as -se, the asadmin short forms for --secure and
+ --echo:
+
+ create-jvm-options -server
+ To create the JVM option -server, instead use the command:
+
+ create-jvm-options -- -server
+
+ Note
+ +----------------------------------------+
+ |If an option name or option value |
+ |contains a colon, the backslash (\) |
+ |must be used to escape the colon in the |
+ |name or value. Other characters might |
+ |also require an escape character. For |
+ |more information about escape |
+ |characters in subcommand options, see |
+ |the asadmin(1M) man page. |
+ +----------------------------------------+
+
+EXAMPLES
+ Example 1, Setting Java System Properties
+ This example sets multiple Java system properties.
+
+ asadmin> create-jvm-options -Dunixlocation=/root/example:
+ -Dvariable=\$HOME:-Dwindowslocation=d\:\\sun\\appserver:-Doption1=-value1
+ created 4 option(s)
+ Command create-jvm-options executed successfully.
+
+ Example 2, Setting a Startup Parameter for the Java Application
+ Launcher
+ This example sets the maximum available heap size to 1024.
+
+ asadmin> create-jvm-options -Xmx1024m
+ created 1 option(s)
+ Command create-jvm-options executed successfully.
+
+ Example 3, Setting Multiple Startup Parameters for the Java Application
+ Launcher
+ This example sets the maximum available heap size to 1024 and
+ requests details about garbage collection.
+
+ asadmin> create-jvm-options "-Xmx1024m:-XX\:+PrintGCDetails"
+ created 1 option(s)
+ Command create-jvm-options executed successfully.
+ In this case, one of the two parameters already exists, so the
+ subcommand reports that only one option was set.
+
+ Example 4, Setting a JVM Startup Parameter for the Profiler
+ This example sets a JVM startup parameter for the profiler.
+
+ asadmin> create-jvm-options --profiler=true -XX\:MaxPermSize=192m
+ created 1 option(s)
+ Command create-jvm-options executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ delete-jvm-options(1), list-jvm-options(1), create-profiler(1),
+ restart-domain(1)
+
+ asadmin(1M)
+
+ For more information about the Java application launcher, see the
+ reference page for the operating system that you are using:
+
+ * Oracle Solaris and Linux: java - the Java application launcher
+ (http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/java.html)
+
+ * Windows: java - the Java application launcher
+ (http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html)
+
+Java EE 8 21 Aug 2017 create-jvm-options(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/create-threadpool.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/create-threadpool.1
new file mode 100644
index 0000000..ce31a2f
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/create-threadpool.1
@@ -0,0 +1,94 @@
+create-threadpool(1) asadmin Utility Subcommands create-threadpool(1)
+
+NAME
+ create-threadpool - adds a thread pool
+
+SYNOPSIS
+ create-threadpool [--help] [--target target]
+ [--maxthreadpoolsize maxthreadpoolsize]
+ [--minthreadpoolsize minthreadpoolsize]
+ [--idletimeout idletimeout] [--maxqueuesize maxqueuesize]
+ [--workqueues workqueues] threadpool-id
+
+DESCRIPTION
+ The create-threadpool subcommand creates a thread pool with the
+ specified name. You can specify maximum and minimum number of threads
+ in the pool, the quantity of messages, and the idle timeout of a
+ thread. The created thread pool can be used for servicing IIOP requests
+ and for resource adapters to service work management requests. A thread
+ pool can be used in multiple resource adapters.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ This option specifies the target on which you are creating the
+ thread pool.
+
+ Valid values are as follows:
+
+ server
+ Creates the thread pool for the default GlassFish Server
+ instance server and is the default value
+
+ configuration-name
+ Creates the thread pool for the named configuration.
+
+ cluster-name
+ Creates the thread pool for every instance in the cluster.
+
+ instance-name
+ Creates the thread pool for a particular instance.
+
+ --maxthreadpoolsize
+ Specifies the maximum number of threads the pool can contain.
+ Default is 5.
+
+ --minthreadpoolsize
+ Specifies the minimum number of threads in the pool. These are
+ created when the thread pool is instantiated. Default is 2.
+
+ --idletimeout
+ Specifies the amount of time in seconds after which idle threads
+ are removed from the pool. Default is 900.
+
+ --maxqueuesize
+ Specifies the maximum number of messages that can be queued until
+ threads are available to process them for a network listener or
+ IIOP listener. A value of -1 specifies no limit. Default is 4096.
+
+ --workqueues
+ Do not specify this option. This option is retained for
+ compatibility with earlier releases. If you specify this option, a
+ syntax error does not occur. Instead, the subcommand runs
+ successfully and displays a warning message that the option is
+ ignored.
+
+OPERANDS
+ threadpool-id
+ An ID for the work queue, for example, threadpool-1.
+
+EXAMPLES
+ Example 1, Creating a Thread Pool
+ This command creates a new thread pool called threadpool-l.
+
+ asadmin> create-threadpool --maxthreadpoolsize 100
+ --minthreadpoolsize 20 --idletimeout 2 threadpool-1
+ Command create-threadpool executed successfully
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ delete-threadpool(1), list-threadpools(1)
+
+ asadmin(1M)
+
+Java EE 8 29 Nov 2010 create-threadpool(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/delete-jvm-options.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/delete-jvm-options.1
new file mode 100644
index 0000000..ae01678
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/delete-jvm-options.1
@@ -0,0 +1,139 @@
+delete-jvm-options(1) asadmin Utility Subcommands delete-jvm-options(1)
+
+NAME
+ delete-jvm-options - removes one or more options for the Java
+ application launcher
+
+SYNOPSIS
+ delete-jvm-options [--help] [--target target] [--profiler={true|false}]
+ (jvm-option-name[=jvm-option-value]) [:jvm-option-name[=jvm-option-name]]*
+
+DESCRIPTION
+ The delete-jvm-options subcommand removes one or more command-line
+ options for the Java application launcher. These options are removed
+ from the Java configuration java—config element or the profiler
+ profiler element of the domain.xml file. To see the Java application
+ launcher options that can be deleted, use the list-jvm-options(1)
+ subcommand.
+
+ The deletion of some options requires a server restart for changes to
+ become effective. Other options are set immediately in the environment
+ of the domain administration server (DAS) and do not require a restart.
+
+ Whether a restart is required depends on the type of option.
+
+ * Restart is not required for Java system properties whose names do
+ not start with -Djava. or -Djavax. (including the trailing
+ period). For example, restart is not required for the following
+ Java system property:
+
+ -Denvironment=Production
+
+ * Restart is required for the following options:
+
+ * Java system properties whose names start with -Djava. or
+ -Djavax. (including the trailing period). For example:
+
+ -Djava.security.manager
+
+ * Startup parameters for the Java application launcher. For
+ example:
+
+ -client
+
+ -Xmx1024m
+
+ -d64
+
+ To restart the DAS, use the restart-domain(1) command.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ Specifies the target from which you are removing Java application
+ launcher options.
+
+ Valid values are as follows:
+
+ server
+ Specifies the DAS (default).
+
+ instance-name
+ Specifies a GlassFish Server instance.
+
+ cluster-name
+ Specifies a cluster.
+
+ configuration-name
+ Specifies a named configuration.
+
+ --profiler
+ Indicates whether the Java application launcher options are for the
+ profiler. The option must have been set for a profiler for this
+ option to be true.
+
+OPERANDS
+ jvm-option-name
+ One or more options delimited by a colon (:). The format of the
+ operand depends on the following:
+
+ * If the option has a name and a value, the format is
+ option-name=value.
+
+ * If the option has only a name, the format is option-name. For
+ example, -Xmx2048m.
+
+ Note
+ +----------------------------------------+
+ |If an option name or option value |
+ |contains a colon, the backslash (\) |
+ |must be used to escape the colon in the |
+ |name or value. Other characters might |
+ |also require an escape character. For |
+ |more information about escape |
+ |characters in subcommand options, see |
+ |the asadmin(1M) man page. |
+ +----------------------------------------+
+
+EXAMPLES
+ Example 1, Deleting Java Application Launcher Options
+ This example removes multiple Java application launcher options.
+
+ asadmin> delete-jvm-options -Doption1=value1
+ "-Doption1=value1:-Doption2=value2"
+ Command delete-jvm-options executed successfully
+
+ Example 2, Deleting a Java Application Launcher Option From the
+ Profiler
+ This example removes a Java application launcher startup parameter
+ for the profiler.
+
+ asadmin> delete-jvm-options --profiler=true -XX:MaxPermSize=192m
+ Command delete-jvm-options executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ create-jvm-options(1), list-jvm-options(1), restart-domain(1)
+
+ asadmin(1M)
+
+ For more information about the Java application launcher, see the
+ reference page for the operating system that you are using:
+
+ * Oracle Solaris and Linux: java - the Java application launcher
+ (http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/java.html)
+
+ * Windows: java - the Java application launcher
+ (http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html)
+
+Java EE 8 21 Aug 2017 delete-jvm-options(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/delete-threadpool.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/delete-threadpool.1
new file mode 100644
index 0000000..20d8df0
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/delete-threadpool.1
@@ -0,0 +1,60 @@
+delete-threadpool(1) asadmin Utility Subcommands delete-threadpool(1)
+
+NAME
+ delete-threadpool - removes a thread pool
+
+SYNOPSIS
+ delete-threadpool [--help] [--target target] threadpool-id
+
+DESCRIPTION
+ Removes the thread pool with the specified ID. This subcommand is
+ supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ This option specifies the target from which you are removing the
+ thread pool.
+
+ Valid values are as follows:
+
+ server
+ Deletes the thread pool for the default GlassFish Server
+ instance server and is the default value.
+
+ configuration-name
+ Deletes the thread pool for the named configuration.
+
+ cluster-name
+ Deletes the thread pool for every instance in the cluster.
+
+ instance-name
+ Deletes the thread pool for a particular instance.
+
+OPERANDS
+ threadpool-id
+ An ID for the work queue, for example, thread-pool1, threadpool-2,
+ and so forth.
+
+EXAMPLES
+ Example 1, Deleting a Thread Pool
+ This example deletes threadpool-l.
+
+ asadmin> delete-threadpool threadpool-1
+ Command delete-threadpool executed successfully
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ create-threadpool(1), list-threadpools(1)
+
+ asadmin(1M)
+
+Java EE 8 29 Nov 2010 delete-threadpool(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/generate-jvm-report.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/generate-jvm-report.1
new file mode 100644
index 0000000..bb5035e
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/generate-jvm-report.1
@@ -0,0 +1,143 @@
+generate-jvm-report(1) asadmin Utility Subcommands generate-jvm-report(1)
+
+NAME
+ generate-jvm-report - shows the JVM machine statistics for a given
+ target instance
+
+SYNOPSIS
+ generate-jvm-report [--help] [--type=jvm-statistic-type] [--target target]
+
+DESCRIPTION
+ The generate-jvm-report subcommand creates a report that shows the
+ threads (dump of stack trace), classes, memory, or loggers for a given
+ target instance, including the domain administration server (DAS). If a
+ type is not specified, a summary report is generated. This subcommand
+ only provides statistics for the GlassFish Server instance processes.
+ This subcommand provides an alternative to sending Ctrl+Break or kill
+ -3 signals to GlassFish Server processes to obtain a stack trace for
+ processes that are hanging.
+
+ The information in the report is obtained from managed beans (MBeans)
+ and MXBeans that are provided in the Java Platform, Standard Edition
+ (Java SE ) or JDK software with which GlassFish Server is being used.
+
+ If GlassFish Server is running in the Java Runtime Environment (JRE)
+ software from JDK release 6 or Java SE 6, additional information is
+ provided. For example:
+
+ * System load on the available processors
+
+ * Object monitors that are currently held or requested by a thread
+
+ * Lock objects that a thread is holding, for example, ReentrantLock
+ objects and ReentrantReadWriteLock objects
+
+ If the JRE software cannot provide this information, the report
+ contains the text NOT_AVAILABLE.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ Specifies the target for which you are showing JVM machine
+ statistics.
+
+ Valid values are as follows:
+
+ server
+ Specifies the DAS (default).
+
+ instance-name
+ Specifies a GlassFish Server instance.
+
+ cluster-name
+ Specifies a cluster.
+
+ configuration-name
+ Specifies a named configuration.
+
+ --type
+ The type of report that is to be generated. Default is summary.
+
+ summary
+ Displays summary information about the threads, classes, and
+ memory (default).
+
+ memory
+ Provides information about heap and non-heap memory
+ consumption, memory pools, and garbage collection statistics
+ for a given target instance.
+
+ class
+ Provides information about the class loader for a given target
+ instance.
+
+ thread
+ Provides information about threads running and the thread dump
+ (stack trace) for a given target instance.
+
+ log
+ Provides information about the loggers that are registered in
+ the Virtual Machine for the Java platform (Java Virtual Machine
+ or JVM machine).The terms "Java Virtual Machine" and "JVM" mean
+ a Virtual Machine for the Java platform.
+
+EXAMPLES
+ Example 1, Obtaining Summary Information for the JVM Machine
+ This example shows a partial listing of a report that is generated
+ if no type is specified. This same report is generated if the
+ summary type is specified.
+
+ asadmin> generate-jvm-report
+ Operating System Information:
+ Name of the Operating System: SunOS
+ Binary Architecture name of the Operating System: sparc, Version: 5.10
+ Number of processors available on the Operating System: 32
+ System load on the available processors for the last minute: 7.921875.
+ (Sum of running and queued runnable entities per minute)
+ General Java Runtime Environment Information for the VM: 64097@sr1-usca-22
+ ...
+ sun.desktop = gnome
+ sun.io.unicode.encoding = UnicodeBig
+ sun.java.launcher = SUN_STANDARD
+ sun.jnu.encoding = ISO646-US
+ sun.management.compiler = HotSpot Client Compiler
+ sun.os.patch.level = unknown
+ user.dir = /home/thisuser/GlassFish/glassfishv3/glassfish/domains/mydomain4/config
+ user.home = /home/thisuser
+ user.language = en
+ user.name = thisuser
+ user.timezone = US/Pacific
+ Command generate-jvm-report executed successfully
+
+ Example 2, Obtaining Information for a Particular JVM Machine Type
+ This example generates a report that shows information on the class
+ loader.
+
+ asadmin> generate-jvm-report --type=class
+ Class loading and unloading in the Java Virtual Machine:
+ Number of classes currently loaded in the Java Virtual Machine: 3,781
+ Number of classes loaded in the Java Virtual Machine since the startup: 3,868
+ Number of classes unloaded from the Java Virtual Machine: 87
+ Just-in-time (JIT) compilation information in the Java Virtual Machine:
+ Java Virtual Machine compilation monitoring allowed: true
+ Name of the Just-in-time (JIT) compiler: HotSpot Client Compiler
+ Total time spent in compilation: 0 Hours 0 Minutes 4 Seconds
+ Command generate-jvm-report executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ create-jvm-options(1), delete-jvm-options(1), list-jvm-options(1)
+
+ asadmin(1M)
+
+Java EE 8 29 Nov 2010 generate-jvm-report(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/list-jobs.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/list-jobs.1
new file mode 100644
index 0000000..443f179
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/list-jobs.1
@@ -0,0 +1,51 @@
+list-jobs(1) asadmin Utility Subcommands list-jobs(1)
+
+NAME
+ list-jobs - lists information about subcommands that were started using
+ asadmin --detach or that contain progress information
+
+SYNOPSIS
+ list-jobs [--help]
+ [job_id]
+
+DESCRIPTION
+ The list-jobs subcommand lists information about subcommands that were
+ started using the asadmin utility option --detach or that contain
+ progress information. The --detach option detaches long-running
+ subcommands and executes them in the background in detach mode.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+OPERANDS
+ job_id
+ The ID of the job for which you want to list information.
+
+EXAMPLES
+ Example 1, Checking Job Status
+ This example provides information about subcommands that were
+ started using asadmin --detach or that contain progress
+ information.
+
+ asadmin> list-jobs
+ JOB ID COMMAND STATE EXIT CODE TIME OF COMPLETION
+ 1 create-cluster COMPLETED SUCCESS 2013-02-15 16:16:16 PST
+ 2 deploy COMPLETED FAILURE 2013-02-15 18:26:30 PST
+ Command list-jobs executed successfully
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ configure-managed-jobs(1), attach(1)
+
+ asadmin(1M)
+
+Java EE 8 06 Feb 2013 list-jobs(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/list-jvm-options.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/list-jvm-options.1
new file mode 100644
index 0000000..c3b1cef
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/list-jvm-options.1
@@ -0,0 +1,97 @@
+list-jvm-options(1) asadmin Utility Subcommands list-jvm-options(1)
+
+NAME
+ list-jvm-options - lists options for the Java application launcher
+
+SYNOPSIS
+ list-jvm-options [--help] [--target target]
+ [--profiler={false|true}]
+
+DESCRIPTION
+ The list-jvm-options subcommand displays a list of command-line options
+ that are passed to the Java application launcher when GlassFish Server
+ is started.
+
+ The options are managed by using the JVM Options page of the
+ Administration Console or by using the create-jvm-options and
+ delete-jvm-options subcommands.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ Specifies the target for which you are listing Java application
+ launcher options.
+
+ Valid values are as follows:
+
+ server
+ Specifies the DAS (default).
+
+ instance-name
+ Specifies a GlassFish Server instance.
+
+ cluster-name
+ Specifies a cluster.
+
+ configuration-name
+ Specifies a named configuration.
+
+ --profiler
+ Specifies whether the Java application launcher options to list are
+ for the profiler. Set this option to true only if a profiler has
+ been configured. If this option is set to true and no profiler is
+ configured, an error occurs. The default is false.
+
+EXAMPLES
+ Example 1, Listing the Java Application Launcher Options
+ This example lists the options that are used by the Java
+ application launcher.
+
+ asadmin> list-jvm-options
+ -Djava.security.auth.login.config=${com.sun.aas.instanceRoot}/config/login.conf
+ -XX: LogVMOutput
+ -XX: UnlockDiagnosticVMOptions
+ -Dcom.sun.enterprise.config.config_environment_factory_class=
+ com.sun.enterprise.config.serverbeans.AppserverConfigEnvironmentFactory
+ -Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/keystore.jks
+ -XX:NewRatio=2
+ -DANTLR_USE_DIRECT_CLASS_LOADING=true
+ -Djava.security.policy=${com.sun.aas.instanceRoot}/config/server.policy
+ -Djdbc.drivers=org.apache.derby.jdbc.ClientDriver
+ -Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/cacerts.jks
+ -client
+ -Djava.ext.dirs=${com.sun.aas.javaRoot}/lib/ext${path.separator}${
+ com.sun.aas.javaRoot}/jre/lib/ext${path.separator}${com.sun.aas.instanceRoot}
+ /lib/ext${path.separator}${com.sun.aas.derbyRoot}/lib
+ -Xmx512m
+ -XX:MaxPermSize=192m
+ -Djava.endorsed.dirs=${com.sun.aas.installRoot}/lib/endorsed
+ -XX:LogFile=${com.sun.aas.instanceRoot}/logs/jvm.log
+ Command list-jvm-options executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ create-jvm-options(1), delete-jvm-options(1)
+
+ asadmin(1M)
+
+ For more information about the Java application launcher, see the
+ reference page for the operating system that you are using:
+
+ * Oracle Solaris and Linux: java - the Java application launcher
+ (http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/java.html)
+
+ * Windows: java - the Java application launcher
+ (http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html)
+
+Java EE 8 21 Aug 2017 list-jvm-options(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/list-threadpools.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/list-threadpools.1
new file mode 100644
index 0000000..69b5b2e
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/commands/list-threadpools.1
@@ -0,0 +1,62 @@
+list-threadpools(1) asadmin Utility Subcommands list-threadpools(1)
+
+NAME
+ list-threadpools - lists all the thread pools
+
+SYNOPSIS
+ list-threadpools [--help] target
+
+DESCRIPTION
+ The list-threadpools subcommand lists the GlassFish Server thread
+ pools.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+OPERANDS
+ target
+ This operand specifies the target for which you are listing thread
+ pools. This operand is required.
+
+ Valid values are as follows:
+
+ server
+ Lists the thread pools for the default GlassFish Server
+ instance server.
+
+ configuration-name
+ Lists the thread pools for the named configuration.
+
+ cluster-name
+ Lists the thread pools for every instance in the cluster.
+
+ instance-name
+ Lists the thread pools for a particular instance.
+
+EXAMPLES
+ Example 1, Listing Thread Pools
+ This example lists the current thread pools for the default
+ instance server.
+
+ asadmin> list-threadpools server
+ admin-thread-pool
+ http-thread-pool
+ thread-pool-1
+ Command list-threadpools executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ create-threadpool(1), delete-threadpool(1)
+
+ asadmin(1M)
+
+Java EE 8 20 Dec 2010 list-threadpools(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/create-profiler.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/create-profiler.1
new file mode 100644
index 0000000..86e9ac1
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/create-profiler.1
@@ -0,0 +1,85 @@
+create-profiler(1) asadmin Utility Subcommands create-profiler(1)
+
+NAME
+ create-profiler - creates the profiler element
+
+SYNOPSIS
+ create-profiler [--help] [--target target_name]
+ [--classpath classpath] [--nativelibpath native_library_path] [--enabled=true]
+ [--property(name=value)[:name=value]*] profiler_name
+
+DESCRIPTION
+ The create-profiler subcommand creates the profiler element. A server
+ instance is tied to the profiler by the profiler element in the Java
+ configuration. Only one profiler exists at a time. If you attempt to
+ create a profiler while one already exists, an error message is
+ displayed.
+
+ For changes to take effect, the server must restarted.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ This option specifies the target on which you are creating a
+ profiler. Valid values are
+
+ server
+ Creates the profiler for the default server instance. This is
+ the default value.
+
+ configuration_name
+ Creates the profiler for the named configuration
+
+ cluster_name
+ Creates the profiler for every server instance in the cluster
+
+ instance_name
+ Creates the profiler for a particular server instance
+
+ --classpath
+ Java classpath string that specifies the classes needed by the
+ profiler.
+
+ --nativelibpath
+ This path is automatically constructed to be a concatenation of the
+ GlassFish Server installation relative path for its native shared
+ libraries, standard JRE native library path, the shell environment
+ setting (LD_LIBRARY_PATH on UNIX) and any path that may be
+ specified in the profile element.
+
+ --enabled
+ Profiler is enabled by default.
+
+ --property
+ Name/value pairs of provider-specific attributes.
+
+OPERANDS
+ profiler_name
+ Name of the profiler.
+
+EXAMPLES
+ Example 1, Creating a Profiler
+ This example creates a profiler named sample_profiler.
+
+ asadmin> create-profiler --classpath /home/appserver/
+ --nativelibpath /u/home/lib --enabled=false
+ --property defaultuser=admin:password=adminadmin sample_profiler
+ Created Profiler with id = sample_profiler
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ delete-profiler(1)
+
+ asadmin(1M)
+
+Java EE 8 22 Dec 2010 create-profiler(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/create-ssl.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/create-ssl.1
new file mode 100644
index 0000000..cb0b81d
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/create-ssl.1
@@ -0,0 +1,175 @@
+create-ssl(1) asadmin Utility Subcommands create-ssl(1)
+
+NAME
+ create-ssl - creates and configures the SSL element in the selected
+ HTTP listener, IIOP listener, or IIOP service
+
+SYNOPSIS
+ create-ssl [--help]
+ [--target target]
+ --type listener_or_service_type
+ --certname cert_name
+ [--ssl2enabled={false|true}] [--ssl2ciphers ss12ciphers]
+ [--ssl3enabled={true|false}] [--tlsenabled={true|false}]
+ [--ssl3tlsciphers ssl3tlsciphers]
+ [--tlsrollbackenabled={true|false}]
+ [--clientauthenabled={false|true}]
+ [listener_id]
+
+DESCRIPTION
+ The create-ssl subcommand creates and configures the SSL element in the
+ selected HTTP listener, IIOP listener, or IIOP service to enable secure
+ communication on that listener/service.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ If an option has a short option name, then the short option precedes
+ the long option name. Short options have one dash whereas long options
+ have two dashes.
+
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ Specifies the target on which you are configuring the ssl element.
+ The following values are valid:
+
+ server
+ Specifies the server in which the iiop-service or HTTP/IIOP
+ listener is to be configured for SSL.
+
+ config
+ Specifies the configuration that contains the HTTP/IIOP
+ listener or iiop-service for which SSL is to be configured.
+
+ cluster
+ Specifies the cluster in which the HTTP/IIOP listener or
+ iiop-service is to be configured for SSL. All the server
+ instances in the cluster will get the SSL configuration for the
+ respective listener or iiop-service.
+
+ instance
+ Specifies the instance in which the HTTP/IIOP listener or
+ iiop-service is to be configured for SSL.
+
+ --type
+ The type of service or listener for which the SSL is created. The
+ type can be:
+
+ * network-listener
+
+ * http-listener
+
+ * iiop-listener
+
+ * iiop-service
+
+ * jmx-connector
+
+ When the type is iiop-service, the ssl-client-config along with the
+ embedded ssl element is created in domain.xml.
+
+ --certname
+ The nickname of the server certificate in the certificate database
+ or the PKCS#11 token. The format of the name in the certificate is
+ tokenname:nickname. For this property, the tokenname: is optional.
+
+ --ssl2enabled
+ Set this property to true to enable SSL2. The default value is
+ false. If both SSL2 and SSL3 are enabled for a virtual server, the
+ server tries SSL3 encryption first. In the event SSL3 encryption
+ fails, the server then tries SSL2 encryption.
+
+ --ssl2ciphers
+ A comma-separated list of the SSL2 ciphers to be used. Ciphers not
+ explicitly listed will be disabled for the target, even if those
+ ciphers are available in the particular cipher suite you are using.
+ If this option is not used, all supported ciphers are assumed to be
+ enabled. Allowed values are:
+
+ * rc4
+
+ * rc4export
+
+ * rc2
+
+ * rc2export
+
+ * idea
+
+ * des
+
+ * desede3
+
+ --ssl3enabled
+ Set this property to false to disable SSL3. The default value is
+ true. If both SSL2 and SSL3 are enabled for a virtual server, the
+ server tries SSL3 encryption first. In the event SSL3 encryption
+ fails, the server then tries SSL2 encryption.
+
+ --tlsenabled
+ Set this property to false to disable TLS. The default value is
+ true It is good practice to enable TLS, which is a more secure
+ version of SSL.
+
+ --ssl3tlsciphers
+ A comma-separated list of the SSL3 and/or TLS ciphers to be used.
+ Ciphers not explicitly listed will be disabled for the target, even
+ if those ciphers are available in the particular cipher suite you
+ are using. If this option is not used, all supported ciphers are
+ assumed to be enabled. Allowed values are:
+
+ * SSL_RSA_WITH_RC4_128_MD5
+
+ * SSL_RSA_WITH_3DES_EDE_CBC_SHA
+
+ * SSL_RSA_WITH_DES_CBC_SHA
+
+ * SSL_RSA_EXPORT_WITH_RC4_40_MD5
+
+ * SSL_RSA_WITH_NULL_MD5
+
+ * SSL_RSA_WITH_RC4_128_SHA
+
+ * SSL_RSA_WITH_NULL_SHA
+
+ --tlsrollbackenabled
+ Set to true (default) to enable TLS rollback. TLS rollback should
+ be enabled for Microsoft Internet Explorer 5.0 and 5.5. This option
+ is only valid when -tlsenabled=true.
+
+ --clientauthenabled
+ Set to true if you want SSL3 client authentication performed on
+ every request independent of ACL-based access control. Default
+ value is false.
+
+OPERANDS
+ listener_id
+ The ID of the HTTP or IIOP listener for which the SSL element is to
+ be created. The listener_id is not required if the --type is
+ iiop-service.
+
+EXAMPLES
+ Example 1, Creating an SSL element for an HTTP listener
+ The following example shows how to create an SSL element for an
+ HTTP listener named http-listener-1.
+
+ asadmin> create-ssl
+ --type http-listener
+ --certname sampleCert http-listener-1
+ Command create-ssl executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ delete-ssl(1)
+
+ asadmin(1M)
+
+Java EE 8 11 Feb 2011 create-ssl(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/create-system-properties.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/create-system-properties.1
new file mode 100644
index 0000000..f35077b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/create-system-properties.1
@@ -0,0 +1,88 @@
+create-system-properties(1) asadmin Utility Subcommands create-system-properties(1)
+
+NAME
+ create-system-properties - adds one or more system property elements
+ that can be referenced elsewhere in the configuration.
+
+SYNOPSIS
+ create-system-properties [--help]
+ [--target target]
+ [name=value)[:name=value]*]
+
+DESCRIPTION
+ The create-system-properties subcommand adds or updates system
+ properties that can be referenced elsewhere on the server.
+
+ GlassFish Server provides hooks where tokens (system properties) can be
+ specified. Because GlassFish Server does not have multiple server
+ elements, you can specify a particular token at any level. When a
+ domain supports multiple servers, the override potential can be
+ exploited. When a domain is started or restarted, all <system-property>
+ elements are resolved and available to the Java Virtual Machine by
+ using the System.setProperty() call on each of them (with its name and
+ value derived from the corresponding attributes of the element). This
+ is analogous to sending the elements as -D parameters on the Java
+ command line.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ The target on which you are creating the system properties.
+
+OPERANDS
+ target
+ The valid targets for this subcommand are instance, cluster,
+ configuration, domain, and server. Server is the default option.
+ Valid values are:
+
+ server
+ Creates the properties on the default server instance. This is
+ the default value.
+
+ domain
+ Creates the properties for all server instances in the default
+ domain.
+
+ configuration_name
+ Creates the properties in the specified configuration.
+
+ cluster_name
+ Creates the properties on all server instances in the specified
+ cluster.
+
+ instance_name
+ Creates the properties on a specified server instance.
+
+ name=value
+ The name value pairs of the system properties to add to the
+ specified target. Multiple system properties must be separated by a
+ : (colon). If a : (colon) appears in the name or value of a system
+ property, it must be escaped with a \ (blackslash). If any system
+ properties were previously defined, they are updated with the new
+ values.
+
+EXAMPLES
+ Example 1, Creating System Properties
+ This example creates a system property associated with an HTTP
+ listener on a server instance named myserver.
+
+ asadmin> create-system-properties --target myserver http-listener-port=1088
+ Command create-system-properties executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ delete-system-property(1), list-system-properties(1)
+
+ asadmin(1M)
+
+Java EE 8 09 Aug 2017 create-system-properties(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/delete-profiler.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/delete-profiler.1
new file mode 100644
index 0000000..8eee3a4
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/delete-profiler.1
@@ -0,0 +1,60 @@
+delete-profiler(1) asadmin Utility Subcommands delete-profiler(1)
+
+NAME
+ delete-profiler - removes the profiler element
+
+SYNOPSIS
+ delete-profiler [--help] [--target target_name]
+
+DESCRIPTION
+ The delete-profiler subcommand deletes the profiler element in the Java
+ configuration. Only one profiler can exist at a time. If you attempt to
+ create a profiler while one already exists, an error message is
+ displayed and the existing profiler must be deleted.
+
+ For changes to take effect, the server must restarted.
+
+ This command is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ This option specifies the target profiler element which you are
+ deleting. Valid values are
+
+ server
+ Deletes the profiler element for the default server instance
+ server and is the default value.
+
+ configuration_name
+ Deletes the profiler element for the named configuration.
+
+ cluster_name
+ Deletes the profiler element for every server instance in the
+ cluster.
+
+ instance_name
+ Deletes the profiler element for a particular server instance.
+
+EXAMPLES
+ Example 1, Deleting a Profile
+ This example deletes the profiler named sample_profiler.
+
+ asadmin> delete-profiler sample_profiler
+ Command delete-profiler executed successfully
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ create-profiler(1)
+
+ asadmin(1M)
+
+Java EE 8 22 Dec 2010 delete-profiler(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/delete-ssl.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/delete-ssl.1
new file mode 100644
index 0000000..6bc809b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/delete-ssl.1
@@ -0,0 +1,89 @@
+delete-ssl(1) asadmin Utility Subcommands delete-ssl(1)
+
+NAME
+ delete-ssl - deletes the SSL element in the selected HTTP listener,
+ IIOP listener, or IIOP service
+
+SYNOPSIS
+ delete-ssl [--help]
+ [--target target]
+ --type listener_or_service_type
+ listener_id
+
+DESCRIPTION
+ The delete-ssl subcommand deletes the SSL element in the selected HTTP
+ listener, IIOP listener, or IIOP service.
+
+ The listener_id is not required if the --type is iiop-service.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ If an option has a short option name, then the short option precedes
+ the long option name. Short options have one dash whereas long options
+ have two dashes.
+
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ Specifies the target on which you are configuring the ssl element.
+ The following values are valid:
+
+ server
+ Specifies the server in which the iiop-service or HTTP/IIOP
+ listener is to be unconfigured for SSL.
+
+ config
+ Specifies the configuration that contains the HTTP/IIOP
+ listener or iiop-service for which SSL is to be unconfigured.
+
+ cluster
+ Specifies the cluster in which the HTTP/IIOP listener or
+ iiop-service is to be unconfigured for SSL. All the server
+ instances in the cluster will get SSL unconfigured for the
+ respective listener or iiop-service.
+
+ instance
+ Specifies the instance in which the HTTP/IIOP listener or
+ iiop-service is to be unconfigured for SSL.
+
+ --type
+ The type of service or listener for which the SSL is deleted. The
+ type must be one of the following types:
+
+ * http-listener
+
+ * iiop-listener
+
+ * iiop-service
+
+OPERANDS
+ listener_id
+ The ID of the listener from which the SSL element is to be deleted.
+
+ The listener_id operand is not required if the --type is
+ iiop-service.
+
+EXAMPLES
+ Example 1, Deleting an SSL element from an HTTP listener
+ The following example shows how to delete an SSL element from an
+ HTTP listener named http-listener-1.
+
+ asadmin> delete-ssl
+ --type http-listener http-listener-1
+ Command delete-ssl executed successfully.
+
+EXIT STATUS
+ 0
+ command executed successfully
+
+ 1
+ error in executing the command
+
+SEE ALSO
+ create-ssl(1)
+
+ asadmin(1M)
+
+Java EE 8 22 Dec 2010 delete-ssl(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/delete-system-property.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/delete-system-property.1
new file mode 100644
index 0000000..17fce64
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/delete-system-property.1
@@ -0,0 +1,52 @@
+delete-system-property(1) asadmin Utility Subcommands delete-system-property(1)
+
+NAME
+ delete-system-property - removes a system property of the domain,
+ configuration, cluster, or server instance, one at a time
+
+SYNOPSIS
+ delete-system-property [--help] [--target target_name ]
+ [property_name]
+
+DESCRIPTION
+ The delete-system-property subcommand deletes a system property of a
+ domain, configuration, cluster, or server instance. Make sure that the
+ system property is not referenced elsewhere in the configuration before
+ deleting it.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --target
+ This option specifies the target on which you are deleting the
+ system properties. The valid targets for this subcommand are
+ instance, cluster, configuration, domain, and server. Server is the
+ default option.
+
+OPERANDS
+ property_name
+ The name of the system property to remove.
+
+EXAMPLES
+ Example 1, Deleting a System Property
+ This example deletes the system property named http-listener-port.
+
+ asadmin> delete-system-property http-listener-port
+ Command delete-system-property executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ create-system-properties(1), list-system-properties(1)
+
+ asadmin(1M)
+
+Java EE 8 09 Aug 2017 delete-system-property(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/get.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/get.1
new file mode 100644
index 0000000..ccccc9c
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/get.1
@@ -0,0 +1,159 @@
+get(1) asadmin Utility Subcommands get(1)
+
+NAME
+ get - gets the values of configurable or monitorable attributes
+
+SYNOPSIS
+ get [--help]
+ [--monitor={true|false}]
+ [--aggregatedataonly={true|false}]
+ (dotted-attribute--name)+
+
+DESCRIPTION
+ The get subcommand uses dotted names to get the names and values of
+ configurable or monitorable attributes for GlassFish Server elements.
+
+ You can use the list(1) subcommand to display the dotted names that
+ represent individual server components and subsystems. For example, a
+ dotted name might be server.applications.web-module. Attributes from
+ the monitoring hierarchy are read-only, but configuration attributes
+ can be modified using the set(1) subcommand. For more detailed
+ information on dotted names, see the dotted-names(5ASC) help page.
+
+ Note
+ +----------------------------------------+
+ | Characters that have special |
+ | meaning to the shell or |
+ | command interpreter, such as |
+ | * (asterisk), should be |
+ | quoted or escaped as |
+ | appropriate to the shell, |
+ | for example, by enclosing |
+ | the argument in quotes. In |
+ | multimode, quotes are needed |
+ | only for arguments that |
+ | include spaces, quotes, or |
+ | backslash. |
+ +----------------------------------------+
+
+ The following list shows common usage of the get subcommand with the *
+ (asterisk):
+
+ get * or get *.*
+ Gets all values on all dotted name prefixes.
+
+ get domain* or get domain*.*
+ Gets all values on the dotted names that begin with domain.
+
+ get *config*.*.*
+ Gets all values on the dotted names that match *config*.*.
+
+ get domain.j2ee-applications.*.ejb-module.*.*
+ Gets all values on all EJB modules of all applications.
+
+ get *web-modules.*.*
+ Gets all values on all web modules whether in an application or
+ standalone.
+
+ get *.*.*.*
+ Gets all values on all dotted names that have four parts.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --monitor, -m
+ Defaults to false. If set to false, the configurable attribute
+ values are returned. If set to true, the monitorable attribute
+ values are returned.
+
+ --aggregatedataonly, -c
+ Aggregates monitoring data for all GlassFish Server instances in a
+ cluster. The default value is false.
+
+OPERANDS
+ dotted-attribute-name
+ Identifies the attribute name in the dotted notation. At least one
+ dotted name attribute is required. The dotted notation is the
+ syntax used to access attributes of configurable entities.
+
+EXAMPLES
+ Example 1, Getting the Attributes of a Configurable Element
+ This example gets the attributes of listener.http-listener-1.
+
+ asadmin> get server.http-service.http-listener.http-listener-1.*
+ server.http-service.http-listener.http-listener-1.acceptor-threads = 1
+ server.http-service.http-listener.http-listener-1.address = 0.0.0.0
+ server.http-service.http-listener.http-listener-1.blocking-enabled = false
+ server.http-service.http-listener.http-listener-1.default-virtual-server = server
+ server.http-service.http-listener.http-listener-1.enabled = true
+ server.http-service.http-listener.http-listener-1.external-port =
+ server.http-service.http-listener.http-listener-1.family = inet
+ server.http-service.http-listener.http-listener-1.id = http-listener-1
+ server.http-service.http-listener.http-listener-1.port = 8080
+ server.http-service.http-listener.http-listener-1.redirect-port =
+ server.http-service.http-listener.http-listener-1.security-enabled = false
+ server.http-service.http-listener.http-listener-1.server-name =
+ server.http-service.http-listener.http-listener-1.xpowered-by = true
+ Command get executed successfully.
+
+ Example 2, Getting Monitorable Objects
+ This example gets the configuration attributes for setting the
+ monitoring level and shows whether they are enabled (LOW or HIGH)
+ or disabled (OFF). The jvm component is enabled for monitoring.
+
+ asadmin> get server.monitoring-service.module-monitoring-levels.*
+ server.monitoring-service.module-monitoring-levels.connector-connection-pool=OFF
+ server.monitoring-service.module-monitoring-levels.connector-service=OFF
+ server.monitoring-service.module-monitoring-levels.d-trace=OFF
+ server.monitoring-service.module-monitoring-levels.ejb-container=OFF
+ server.monitoring-service.module-monitoring-levels.http-service=OFF
+ server.monitoring-service.module-monitoring-levels.jdbc-connection-pool=OFF
+ server.monitoring-service.module-monitoring-levels.jms-service=OFF
+ server.monitoring-service.module-monitoring-levels.jvm=HIGH
+ server.monitoring-service.module-monitoring-levels.orb=OFF
+ server.monitoring-service.module-monitoring-levels.thread-pool=OFF
+ server.monitoring-service.module-monitoring-levels.transaction-service=OFF
+ server.monitoring-service.module-monitoring-levels.web-container=OFF
+ Command get executed successfully.
+
+ Example 3, Getting Attributes and Values for a Monitorable Object
+ This example gets all attributes and values of the jvm monitorable
+ object.
+
+ asadmin> get --monitor server.jvm.*
+ server.jvm.HeapSize_Current = 45490176
+ server.jvm.HeapSize_Description = Describes JvmHeapSize
+ server.jvm.HeapSize_HighWaterMark = 45490176
+ server.jvm.HeapSize_LastSampleTime = 1063217002433
+ server.jvm.HeapSize_LowWaterMark = 0
+ server.jvm.HeapSize_LowerBound = 0
+ server.jvm.HeapSize_Name = JvmHeapSize
+ server.jvm.HeapSize_StartTime = 1063238840055
+ server.jvm.HeapSize_Unit = bytes
+ server.jvm.HeapSize_UpperBound = 531628032
+ server.jvm.UpTime_Count = 1063238840100
+ server.jvm.UpTime_Description = Describes JvmUpTime
+ server.jvm.UpTime_LastSampleTime = 1-63238840070
+ server.jvm.UpTime_Name = JvmUpTime
+ server.jvm.UpTime_StartTime = 1063217002430
+ server.jvm.UpTime_Unit = milliseconds
+ Command get executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ list(1), set(1)
+
+ dotted-names(5ASC)
+
+ asadmin(1M)
+
+ Oracle GlassFish Server Administration Guide
+
+Java EE 8 12 Feb 2013 get(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list-containers.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list-containers.1
new file mode 100644
index 0000000..8844d01
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list-containers.1
@@ -0,0 +1,51 @@
+list-containers(1) asadmin Utility Subcommands list-containers(1)
+
+NAME
+ list-containers - lists application containers
+
+SYNOPSIS
+ list-containers [--help]
+
+DESCRIPTION
+ The list-containers subcommand displays a list of application
+ containers.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+EXAMPLES
+ Example 1, Listing the Application Containers
+ This example lists the current application containers.
+
+ asadmin> list-containers
+ List all known application containers
+ Container : grizzly
+ Container : ejb
+ Container : webservices
+ Container : ear
+ Container : appclient
+ Container : connector
+ Container : jpa
+ Container : web
+ Container : osgi
+ Container : security
+ Container : webbeans
+
+ Command list-containers executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ list-commands(1), list-components(1), list-modules(1)
+
+ asadmin(1M)
+
+Java EE 8 9 Oct 2009 list-containers(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list-modules.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list-modules.1
new file mode 100644
index 0000000..a4d47c8
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list-modules.1
@@ -0,0 +1,63 @@
+list-modules(1) asadmin Utility Subcommands list-modules(1)
+
+NAME
+ list-modules - lists GlassFish Server modules
+
+SYNOPSIS
+ list-modules [--help]
+
+DESCRIPTION
+ The list-modules subcommand displays a list of modules that are
+ accessible to the GlassFish Server module subsystem. The version of
+ each module is shown.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+EXAMPLES
+ Example 1, Listing GlassFish Server Modules
+ This example provides a partial listing of modules that are
+ accessible to the GlassFish Server module subsystem
+
+ asadmin> list-modules
+ List Of Modules
+
+ Module : org.glassfish.transaction.jts:3.0.0.b66
+ Module Characteristics : List of Jars implementing the module
+ Jar : file:/home/gfuser/GlassFish/glassfishv3/glassfish/modules/jts.jar
+ Module Characteristics : Provides to following services
+ Module Characteristics : List of imported modules
+ Imports : org.glassfish.transaction.jts:3.0.0.b66
+ Module : com.sun.enterprise.tiger-types-osgi:0.3.96
+ Module : org.glassfish.bean-validator:3.0.0.JBoss-400Beta3A
+ Module : org.glassfish.core.kernel:3.0.0.b66
+ Module Characteristics : Provides to following services
+ Module Characteristics : List of imported modules
+ Imports : org.glassfish.core.kernel:3.0.0.b66
+ Module Characteristics : List of Jars implementing the module
+ Jar : file:/home/gfuser/GlassFish/glassfishv3/glassfish/modules/kernel.jar
+ Module : org.glassfish.common.util:3.0.0.b66
+ Module Characteristics : List of Jars implementing the module
+ Jar : file:/home/gfuser/GlassFish/glassfishv3/glassfish/modules/common-util.jar
+ Module Characteristics : Provides to following services
+ Module Characteristics : List of imported modules
+ Imports : org.glassfish.common.util:3.0.0.b66
+ ...
+ Command list-modules executed successfully
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ list-commands(1), list-components(1), list-containers(1)
+
+ asadmin(1M)
+
+Java EE 8 9 Oct 2009 list-modules(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list-system-properties.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list-system-properties.1
new file mode 100644
index 0000000..3dff5dd
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list-system-properties.1
@@ -0,0 +1,63 @@
+list-system-properties(1) asadmin Utility Subcommands list-system-properties(1)
+
+NAME
+ list-system-properties - lists the system properties of the domain,
+ configuration, cluster, or server instance
+
+SYNOPSIS
+ list-system-properties [--help] [target]
+
+DESCRIPTION
+ The list-system-properties subcommand lists the system properties of a
+ domain, configuration, cluster, or server instance.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+OPERANDS
+ target
+ This restricts the listing to system properties for a specific
+ target. Valid values are:
+
+ domain
+ Lists the system properties defined for the domain.
+
+ configuration_name
+ Lists the system properties for the named configuration as well
+ as those the cluster inherits from the domain.
+
+ cluster_name
+ Lists the system properties defined for the named cluster as
+ well as those the cluster. inherits from its configuration and
+ the domain.
+
+ instance_name
+ Lists the system properties defined for the named server
+ instance as well as those the server inherits from its cluster
+ (if the instance is clustered), its configuration, and the
+ domain.
+
+EXAMPLES
+ Example 1, Listing System Properties
+ This example lists the system properties on localhost.
+
+ asadmin> list-system-properties
+ http-listener-port=1088
+ Command list-system-properties executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ create-system-properties(1), delete-system-property(1)
+
+ asadmin(1M)
+
+Java EE 8 09 Aug 2017 list-system-properties(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list.1
new file mode 100644
index 0000000..8cc8d97
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/list.1
@@ -0,0 +1,177 @@
+list(1) asadmin Utility Subcommands list(1)
+
+NAME
+ list - lists configurable or monitorable elements
+
+SYNOPSIS
+ list [--help] [--monitor={false|true}]
+ [dotted-parent-attribute-name]
+
+DESCRIPTION
+ The list subcommand lists configurable and monitorable attributes of
+ GlassFish Server.
+
+ The output of the list subcommand is a list of the dotted names that
+ represent individual server components and subsystems. For example,
+ server.applications.web-module. After you know the particular component
+ or subsystem, you can then use the get subcommand to access any
+ attributes, and the set subcommand to modify configurable attributes.
+
+ The following rules apply to dotted names in a list subcommand:
+
+ Note
+ +----------------------------------------+
+ | Characters that have special |
+ | meaning to the shell or |
+ | command interpreter, such as |
+ | * (asterisk), should be |
+ | quoted or escaped as |
+ | appropriate to the shell, |
+ | for example, by enclosing |
+ | the argument in quotes. In |
+ | multimode, quotes are needed |
+ | only for arguments that |
+ | include spaces, quotes, or |
+ | backslash. |
+ +----------------------------------------+
+
+ * Any list subcommand that has a dotted name that is not followed by
+ a wildcard (*) lists the current node's immediate children. For
+ example, the following command lists all immediate children
+ belonging to the server node:
+
+ asadmin> list server
+
+ * Any list subcommand that has a dotted name followed by a
+ wildcard(*) lists a hierarchical tree of child nodes from the
+ current node. For example, the following command lists all child
+ nodes of applications and their subsequent child nodes, and so on:
+
+ asadmin> list server.applications.*
+
+ * Any list subcommand that has a dotted name preceded or followed by
+ a wildcard (*) of the form *dotted name or dottedname* lists all
+ nodes and their child nodes that match the regular expression
+ created by the provided matching pattern.
+
+ For detailed information about dotted names, see the dotted-names(5ASC)
+ help page.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+ --monitor, -m
+ Defaults to false. If set to false, the configurable attribute
+ values are returned. If set to true, the monitorable attribute
+ values are returned.
+
+OPERANDS
+ dotted-parent-element-name
+ Configurable or monitorable element name
+
+EXAMPLES
+ Example 1, Listing Dotted Names of Configurable Elements
+ This example lists the elements that can be configured.
+
+ asadmin> list *
+ applications
+ configs
+ configs.config.server-config
+ configs.config.server-config.admin-service
+ configs.config.server-config.admin-service.das-config
+ configs.config.server-config.admin-service.jmx-connector.system
+ configs.config.server-config.admin-service.property.adminConsoleContextRoot
+ configs.config.server-config.admin-service.property.adminConsoleDownloadLocation
+ configs.config.server-config.admin-service.property.ipsRoot
+ configs.config.server-config.ejb-container
+ configs.config.server-config.ejb-container.ejb-timer-service
+ configs.config.server-config.http-service
+ configs.config.server-config.http-service.access-log
+ configs.config.server-config.http-service.virtual-server.__asadmin
+ configs.config.server-config.http-service.virtual-server.server
+ configs.config.server-config.iiop-service
+ configs.config.server-config.iiop-service.iiop-listener.SSL
+ configs.config.server-config.iiop-service.iiop-listener.SSL.ssl
+ configs.config.server-config.iiop-service.iiop-listener.SSL_MUTUALAUTH
+ configs.config.server-config.iiop-service.iiop-listener.SSL_MUTUALAUTH.ssl
+ configs.config.server-config.iiop-service.iiop-listener.orb-listener-1
+ configs.config.server-config.iiop-service.orb
+ configs.config.server-config.java-config
+ configs.config.server-config.jms-service
+ configs.config.server-config.jms-service.jms-host.default_JMS_host
+ ...
+ property.administrative.domain.name
+ resources
+ resources.jdbc-connection-pool.DerbyPool
+ resources.jdbc-connection-pool.DerbyPool.property.DatabaseName
+ resources.jdbc-connection-pool.DerbyPool.property.Password
+ resources.jdbc-connection-pool.DerbyPool.property.PortNumber
+ resources.jdbc-connection-pool.DerbyPool.property.User
+ resources.jdbc-connection-pool.DerbyPool.property.connectionAttributes
+ resources.jdbc-connection-pool.DerbyPool.property.serverName
+ resources.jdbc-connection-pool.__TimerPool
+ resources.jdbc-connection-pool.__TimerPool.property.connectionAttributes
+ resources.jdbc-connection-pool.__TimerPool.property.databaseName
+ resources.jdbc-resource.jdbc/__TimerPool
+ resources.jdbc-resource.jdbc/__default
+ servers
+ servers.server.server
+ servers.server.server.resource-ref.jdbc/__TimerPool
+ servers.server.server.resource-ref.jdbc/__default
+ system-applications
+ Command list executed successfully.
+
+ Example 2, Listing Attributes of a Configurable Element
+ This example lists the attributes of the web container.
+
+ asadmin> list configs.config.server-config.web-container
+ configs.config.server-config.web-container
+ configs.config.server-config.web-container.session-config
+ Command list executed successfully.
+
+ Example 3, Listing Dotted Names of Monitorable Objects
+ This example lists the names of the monitorable objects that are
+ enabled for monitoring.
+
+ asadmin> list --monitor *
+ server.jvm
+ server.jvm.class-loading-system
+ server.jvm.compilation-system
+ server.jvm.garbage-collectors
+ server.jvm.garbage-collectors.Copy
+ server.jvm.garbage-collectors.MarkSweepCompact
+ server.jvm.memory
+ server.jvm.operating-system
+ server.jvm.runtime
+ server.network
+ server.network.admin-listener
+ server.network.admin-listener.connections
+ server.network.admin-listener.file-cache
+ server.network.admin-listener.keep-alive
+ server.network.admin-listener.thread-pool
+ server.network.http-listener-1
+ server.network.http-listener-1.connections
+ server.network.http-listener-1.file-cache
+ server.network.http-listener-1.keep-alive
+ server.network.http-listener-1.thread-pool
+ server.transaction-service
+ Command list executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ get(1), set(1)
+
+ dotted-names(5ASC)
+
+ asadmin(1M)
+
+ Oracle GlassFish Server Administration Guide
+
+Java EE 8 14 Sep 2009 list(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/set.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/set.1
new file mode 100644
index 0000000..a3131e9b
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/set.1
@@ -0,0 +1,96 @@
+set(1) asadmin Utility Subcommands set(1)
+
+NAME
+ set - sets the values of configurable attributes
+
+SYNOPSIS
+ set [--help] attribute-name=value
+
+DESCRIPTION
+ The set subcommand uses dotted names to modify the values of one or
+ more configurable attributes.
+
+ Attributes from the monitoring hierarchy are read-only, but
+ configuration attributes can be modified. You can use the list(1)
+ subcommand to display the dotted names that represent individual server
+ components and subsystems. For example, a dotted name might be
+ server.applications.web-module. After you discover the particular
+ component or subsystem, you can then use the get subcommand to access
+ the attributes. For more detailed information on dotted names, see the
+ dotted-names(5ASC) help page.
+
+ Note
+ +----------------------------------------+
+ | Characters that have special |
+ | meaning to the shell or |
+ | command interpreter, such as |
+ | * (asterisk), should be |
+ | quoted or escaped as |
+ | appropriate to the shell, |
+ | for example, by enclosing |
+ | the argument in quotes. In |
+ | multimode, quotes are needed |
+ | only for arguments that |
+ | include spaces, quotes, or |
+ | backslash. |
+ +----------------------------------------+
+
+ By modifying attributes, you can enable and disable services, and
+ customize how an existing element functions. An asadmin subcommand is
+ provided to update some elements. For example, update-password-alias.
+ However, to update other elements, you must use the set command. For
+ example, you create a JDBC connection pool by using the
+ create-jdbc-connection-pool subcommand. To change attribute settings
+ later, you use the set command.
+
+ Any change made by using the asadmin utility subcommands or the
+ Administration Console are automatically applied to the associated
+ GlassFish Server configuration file.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+OPERANDS
+ attribute-name=value
+ Identifies the full dotted name of the attribute name and its
+ value.
+
+EXAMPLES
+ Example 1, Setting a JDBC Connection Pool Attribute
+ This example changes the steady pool size of the DerbyPool
+ connection pool to 9.
+
+ asadmin> set resources.jdbc-connection-pool.DerbyPool.steady-pool-size=9
+ Command set executed successfully.
+
+ Example 2, Enabling the Monitoring Service for a Monitorable Object
+ This example enables monitoring for the JVM.
+
+ asadmin> set server.monitoring-service.module-monitoring-levels.jvm=HIGH
+ Command set executed successfully.
+
+ Example 3, Turning on Automatic Recovery for the Transaction Service
+ This example turns on automatic recovery for the transaction
+ service.
+
+ asadmin> set server.transaction-service.automatic-recovery=true
+ Command set executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ get(1), list(1)
+
+ dotted-names(5ASC)
+
+ asadmin(1M)
+
+ Oracle GlassFish Server Administration Guide
+
+Java EE 8 10 Sep 2009 set(1)
diff --git a/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/uptime.1 b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/uptime.1
new file mode 100644
index 0000000..1bd2124
--- /dev/null
+++ b/nucleus/core/kernel/src/main/manpages/com/sun/enterprise/v3/admin/uptime.1
@@ -0,0 +1,41 @@
+uptime(1) asadmin Utility Subcommands uptime(1)
+
+NAME
+ uptime - returns the length of time that the DAS has been running
+
+SYNOPSIS
+ uptime [--help]
+
+DESCRIPTION
+ The uptime subcommand returns the length of time that the domain
+ administration server (DAS) has been running since it was last
+ restarted.
+
+ This subcommand is supported in remote mode only.
+
+OPTIONS
+ --help, -?
+ Displays the help text for the subcommand.
+
+EXAMPLES
+ Example 1, Showing How Long the DAS Has Been Running
+ This example shows the length of time that the DAS has been
+ running.
+
+ asadmin> uptime
+ Uptime: 2 days, 1 hours, 30 minutes, 18 seconds, Total milliseconds: 178218706
+ Command uptime executed successfully.
+
+EXIT STATUS
+ 0
+ subcommand executed successfully
+
+ 1
+ error in executing the subcommand
+
+SEE ALSO
+ list-domains(1), start-domain(1), stop-domain(1)
+
+ asadmin(1M)
+
+Java EE 8 8 Sep 2009 uptime(1)
diff --git a/nucleus/core/kernel/src/main/resources/META-INF/services/org.glassfish.hk2.bootstrap.PopulatorPostProcessor b/nucleus/core/kernel/src/main/resources/META-INF/services/org.glassfish.hk2.bootstrap.PopulatorPostProcessor
new file mode 100644
index 0000000..8b19782
--- /dev/null
+++ b/nucleus/core/kernel/src/main/resources/META-INF/services/org.glassfish.hk2.bootstrap.PopulatorPostProcessor
@@ -0,0 +1 @@
+org.glassfish.kernel.embedded.EmbeddedInhabitantsParser
diff --git a/nucleus/core/kernel/src/main/resources/com/sun/enterprise/v3/admin/commands/.gitkeep_empty_dir b/nucleus/core/kernel/src/main/resources/com/sun/enterprise/v3/admin/commands/.gitkeep_empty_dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nucleus/core/kernel/src/main/resources/com/sun/enterprise/v3/admin/commands/.gitkeep_empty_dir
diff --git a/nucleus/core/kernel/src/main/resources/com/sun/logging/enterprise/system/core/.gitkeep_empty_dir b/nucleus/core/kernel/src/main/resources/com/sun/logging/enterprise/system/core/.gitkeep_empty_dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nucleus/core/kernel/src/main/resources/com/sun/logging/enterprise/system/core/.gitkeep_empty_dir
diff --git a/nucleus/core/kernel/src/main/resources/org/glassfish/embed/domain.xml b/nucleus/core/kernel/src/main/resources/org/glassfish/embed/domain.xml
new file mode 100644
index 0000000..76db7d7
--- /dev/null
+++ b/nucleus/core/kernel/src/main/resources/org/glassfish/embed/domain.xml
@@ -0,0 +1,175 @@
+<!--
+
+ Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v. 2.0, which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ This Source Code may also be made available under the following Secondary
+ Licenses when the conditions for such availability set forth in the
+ Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ version 2 with the GNU Classpath Exception, which is available at
+ https://www.gnu.org/software/classpath/license.html.
+
+ SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<domain log-root="${com.sun.aas.instanceRoot}/logs" application-root="${com.sun.aas.instanceRoot}/applications" version="10.0">
+ <security-configurations>
+ <authorization-service default="true" name="authorizationService">
+ <security-provider name="simpleAuthorization" type="Simple" provider-name="simpleAuthorizationProvider">
+ <authorization-provider-config support-policy-deploy="false" name="simpleAuthorizationProviderConfig"></authorization-provider-config>
+ </security-provider>
+ </authorization-service>
+ </security-configurations>
+ <system-applications />
+ <applications />
+ <resources>
+ <jdbc-resource pool-name="__TimerPool" jndi-name="jdbc/__TimerPool" object-type="system-admin" />
+ <jdbc-resource pool-name="DerbyPool" jndi-name="jdbc/__default" object-type="system-all" />
+ <jdbc-connection-pool name="__TimerPool" datasource-classname="org.apache.derby.jdbc.EmbeddedXADataSource" res-type="javax.sql.XADataSource">
+ <property value="${com.sun.aas.instanceRoot}/lib/databases/ejbtimer" name="databaseName" />
+ <property value=";create=true" name="connectionAttributes" />
+ </jdbc-connection-pool>
+ <jdbc-connection-pool is-isolation-level-guaranteed="false" name="DerbyPool" datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource" res-type="javax.sql.DataSource">
+ <property name="databaseName" value="${com.sun.aas.instanceRoot}/lib/databases/embedded_default" />
+ <property name="connectionAttributes" value=";create=true" />
+ </jdbc-connection-pool>
+ </resources>
+ <servers>
+ <server name="server" config-ref="server-config">
+ <resource-ref ref="jdbc/__TimerPool" />
+ <resource-ref ref="jdbc/__default" />
+ </server>
+ </servers>
+ <configs>
+ <config name="server-config">
+ <http-service>
+ <access-log rotation-interval-in-minutes="15" rotation-suffix="yyyy-MM-dd" />
+ <virtual-server id="server" network-listeners="http-listener, https-listener" />
+ </http-service>
+ <iiop-service>
+ <orb use-thread-pool-ids="thread-pool-1" />
+ <iiop-listener address="0.0.0.0" port="3700" id="orb-listener-1" />
+ <iiop-listener security-enabled="true" address="0.0.0.0" port="3820" id="SSL">
+ <ssl classname="com.sun.enterprise.security.ssl.GlassfishSSLImpl" cert-nickname="s1as" />
+ </iiop-listener>
+ <iiop-listener security-enabled="true" address="0.0.0.0" port="3920" id="SSL_MUTUALAUTH">
+ <ssl classname="com.sun.enterprise.security.ssl.GlassfishSSLImpl" cert-nickname="s1as" client-auth-enabled="true" />
+ </iiop-listener>
+ </iiop-service>
+ <admin-service type="das-and-server" system-jmx-connector-name="system">
+ <jmx-connector enabled="false" auth-realm-name="admin-realm" security-enabled="false" address="0.0.0.0" port="8686" name="system" />
+ <das-config autodeploy-enabled="false" dynamic-reload-enabled="true" deploy-xml-validation="full" autodeploy-dir="${com.sun.aas.instanceRoot}/autodeploy" />
+ <property value="/admin" name="adminConsoleContextRoot" />
+ <property value="${com.sun.aas.installRoot}/lib/install/applications/admingui.war" name="adminConsoleDownloadLocation" />
+ <property value="${com.sun.aas.installRoot}/.." name="ipsRoot" />
+ </admin-service>
+ <connector-service shutdown-timeout-in-seconds="30">
+ </connector-service>
+ <ejb-container steady-pool-size="0" max-pool-size="32" session-store="${com.sun.aas.instanceRoot}/session-store" pool-resize-quantity="8">
+ <ejb-timer-service />
+ </ejb-container>
+ <mdb-container steady-pool-size="0" max-pool-size="32" pool-resize-quantity="8" >
+ </mdb-container>
+ <jms-service type="EMBEDDED" default-jms-host="default_JMS_host">
+ <jms-host name="default_JMS_host" host="localhost" port="7676" admin-user-name="admin" admin-password="admin" lazy-init="false"/>
+ </jms-service>
+ <log-service file="${com.sun.aas.instanceRoot}/logs/server.log" log-rotation-limit-in-bytes="2000000">
+ <module-log-levels />
+ </log-service>
+ <security-service activate-default-principal-to-role-mapping="true" jacc="simple">
+ <auth-realm classname="com.sun.enterprise.security.auth.realm.file.FileRealm" name="admin-realm">
+ <property value="${com.sun.aas.instanceRoot}/config/admin-keyfile" name="file" />
+ <property value="fileRealm" name="jaas-context" />
+ </auth-realm>
+ <auth-realm classname="com.sun.enterprise.security.auth.realm.file.FileRealm" name="file">
+ <property value="${com.sun.aas.instanceRoot}/config/keyfile" name="file" />
+ <property value="fileRealm" name="jaas-context" />
+ </auth-realm>
+ <auth-realm classname="com.sun.enterprise.security.auth.realm.certificate.CertificateRealm" name="certificate" />
+ <jacc-provider policy-configuration-factory-provider="com.sun.enterprise.security.provider.PolicyConfigurationFactoryImpl" policy-provider="com.sun.enterprise.security.provider.PolicyWrapper" name="default">
+ <property value="${com.sun.aas.instanceRoot}/generated/policy" name="repository" />
+ </jacc-provider>
+ <jacc-provider policy-configuration-factory-provider="com.sun.enterprise.security.jacc.provider.SimplePolicyConfigurationFactory" policy-provider="com.sun.enterprise.security.jacc.provider.SimplePolicyProvider" name="simple" />
+ <audit-module classname="com.sun.enterprise.security.ee.Audit" name="default">
+ <property value="false" name="auditOn" />
+ </audit-module>
+ <message-security-config auth-layer="SOAP">
+ <provider-config provider-id="XWS_ClientProvider" class-name="com.sun.xml.wss.provider.ClientSecurityAuthModule" provider-type="client">
+ <request-policy auth-source="content" />
+ <response-policy auth-source="content" />
+ <property value="s1as" name="encryption.key.alias" />
+ <property value="s1as" name="signature.key.alias" />
+ <property value="false" name="dynamic.username.password" />
+ <property value="false" name="debug" />
+ </provider-config>
+ <provider-config provider-id="ClientProvider" class-name="com.sun.xml.wss.provider.ClientSecurityAuthModule" provider-type="client">
+ <request-policy auth-source="content" />
+ <response-policy auth-source="content" />
+ <property value="s1as" name="encryption.key.alias" />
+ <property value="s1as" name="signature.key.alias" />
+ <property value="false" name="dynamic.username.password" />
+ <property value="false" name="debug" />
+ <property value="${com.sun.aas.instanceRoot}/config/wss-server-config-1.0.xml" name="security.config" />
+ </provider-config>
+ <provider-config provider-id="XWS_ServerProvider" class-name="com.sun.xml.wss.provider.ServerSecurityAuthModule" provider-type="server">
+ <request-policy auth-source="content" />
+ <response-policy auth-source="content" />
+ <property value="s1as" name="encryption.key.alias" />
+ <property value="s1as" name="signature.key.alias" />
+ <property value="false" name="debug" />
+ </provider-config>
+ <provider-config provider-id="ServerProvider" class-name="com.sun.xml.wss.provider.ServerSecurityAuthModule" provider-type="server">
+ <request-policy auth-source="content" />
+ <response-policy auth-source="content" />
+ <property value="s1as" name="encryption.key.alias" />
+ <property value="s1as" name="signature.key.alias" />
+ <property value="false" name="debug" />
+ <property value="${com.sun.aas.instanceRoot}/config/wss-server-config-1.0.xml" name="security.config" />
+ </provider-config>
+ </message-security-config>
+ <property value="SHA-256" name="default-digest-algorithm" />
+ </security-service>
+ <monitoring-service>
+ <module-monitoring-levels />
+ </monitoring-service>
+ <transaction-service tx-log-dir="${com.sun.aas.instanceRoot}/logs" >
+ </transaction-service>
+ <java-config>
+ <jvm-options>-Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/keystore.jks</jvm-options>
+ <jvm-options>-Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/cacerts.jks</jvm-options>
+ <jvm-options>-Dorg.glassfish.jms.InitializeOnDemand=true</jvm-options>
+ </java-config>
+ <network-config>
+ <protocols>
+ <protocol name="http-listener">
+ <http default-virtual-server="server" max-connections="250">
+ <file-cache enabled="false"></file-cache>
+ </http>
+ </protocol>
+ <protocol security-enabled="true" name="https-listener">
+ <http default-virtual-server="server" max-connections="250">
+ <file-cache enabled="false"></file-cache>
+ </http>
+ <ssl classname="com.sun.enterprise.security.ssl.GlassfishSSLImpl" ssl3-enabled="false" cert-nickname="s1as"></ssl>
+ </protocol>
+ </protocols>
+ <network-listeners>
+ <network-listener port="0" protocol="http-listener" transport="tcp" name="http-listener" thread-pool="http-thread-pool" enabled="false" />
+ <network-listener port="0" protocol="https-listener" transport="tcp" name="https-listener" thread-pool="http-thread-pool" enabled="false" />
+ </network-listeners>
+ <transports>
+ <transport name="tcp"></transport>
+ </transports>
+ </network-config>
+ <thread-pools>
+ <thread-pool name="http-thread-pool" max-queue-size="4096"></thread-pool>
+ <thread-pool name="thread-pool-1" max-thread-pool-size="200"/>
+ </thread-pools>
+ </config>
+ </configs>
+ <property name="administrative.domain.name" value="domain1"/>
+</domain>
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/AdminAdapterTest.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/AdminAdapterTest.java
new file mode 100644
index 0000000..86e9b7c
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/AdminAdapterTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.junit.Before;
+import org.glassfish.api.admin.ParameterMap;
+import com.sun.enterprise.v3.admin.AdminAdapter;
+import java.util.Properties;
+
+
+/**
+ * junit test to test AdminAdapter class
+ */
+public class AdminAdapterTest {
+ private AdminAdapter aa = null;
+
+ @Test
+ public void extractParametersTest() {
+ ParameterMap props = aa.extractParameters("uniquetablenames=false&createtables=true&target=server&libraries=foo.jar&dbvendorname=test&deploymentplan=test");
+ Properties correctProps = new Properties();
+ correctProps.put("uniquetablenames", "false");
+ correctProps.put("createtables", "true");
+ correctProps.put("target", "server");
+ correctProps.put("libraries", "foo.jar");
+ correctProps.put("dbvendorname", "test");
+ correctProps.put("deploymentplan", "test");
+ for (String prop : correctProps.stringPropertyNames()) {
+ assertEquals("compare Properties",
+ correctProps.getProperty(prop), props.getOne(prop));
+ }
+ }
+
+ @Before
+ public void setup() {
+ aa = new PublicAdminAdapter();
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/AdminCommandContextTest.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/AdminCommandContextTest.java
new file mode 100644
index 0000000..7fa0a7a
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/AdminCommandContextTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.AdminCommandContextImpl;
+import org.junit.Test;
+
+import com.sun.enterprise.v3.common.DoNothingActionReporter;
+import com.sun.enterprise.v3.common.PlainTextActionReporter;
+
+public class AdminCommandContextTest {
+
+ @Test
+ public void testSerialization() throws IOException, ClassNotFoundException {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(os);
+ ActionReport report = new PlainTextActionReporter();
+ AdminCommandContext context = new AdminCommandContextImpl(null /* logger */, report);
+ report.setFailureCause(new RuntimeException("Test"));
+ oos.writeObject(context);
+ ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(is);
+ AdminCommandContext restored = (AdminCommandContextImpl) ois.readObject();
+ assertEquals("failureCause", "Test", restored.getActionReport().getFailureCause().getMessage());
+ // context.setPayload
+ }
+
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/AnotherPublicMethod.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/AnotherPublicMethod.java
new file mode 100644
index 0000000..838443e
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/AnotherPublicMethod.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.ActionReport;
+
+/**
+ * public command with no visibility annotation
+ *
+ * @author Jerome Dochez
+ */
+@Service(name="notannoated-public-command")
+public class AnotherPublicMethod implements AdminCommand {
+ public void execute(AdminCommandContext context) {
+ context.getActionReport().setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/CommandRunnerTest.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/CommandRunnerTest.java
new file mode 100644
index 0000000..054b46d
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/CommandRunnerTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import static org.junit.Assert.*;
+
+import org.glassfish.common.util.admin.CommandModelImpl;
+import org.glassfish.hk2.api.MultiException;
+import org.junit.Test;
+import org.junit.Before;
+import org.glassfish.api.Param;
+import org.glassfish.api.admin.ParameterMap;
+
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.CommandModel;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * junit test to test CommandRunner class
+ */
+public class CommandRunnerTest {
+ private CommandRunnerImpl cr = null;
+
+ @Test
+ public void getUsageTextTest() {
+ String expectedUsageText = "Usage: dummy-admin --foo=foo [--bar=false] --hello=there world ";
+ DummyAdminCommand dac = new DummyAdminCommand();
+ CommandModel model = new CommandModelImpl(DummyAdminCommand.class);
+ String actualUsageText = cr.getUsageText(model);
+ assertEquals(expectedUsageText, actualUsageText);
+ }
+
+ @Test
+ public void validateParametersTest() {
+ ParameterMap params = new ParameterMap();
+ params.set("foo", "bar");
+ params.set("hello", "world");
+ params.set("one", "two");
+ try {
+ cr.validateParameters(new CommandModelImpl(DummyAdminCommand.class), params);
+ }
+ catch (MultiException ce) {
+ String expectedMessage = " Invalid option: one";
+ assertTrue(ce.getMessage().contains(expectedMessage));
+ }
+ }
+
+ @Test
+ public void skipValidationTest() {
+ DummyAdminCommand dac = new DummyAdminCommand();
+ assertFalse(cr.skipValidation(dac));
+ SkipValidationCommand svc = new SkipValidationCommand();
+ assertTrue(cr.skipValidation(svc));
+ }
+
+ @Before
+ public void setup() {
+ cr = new CommandRunnerImpl();
+ }
+
+ //mock-up DummyAdminCommand object
+ @Service(name="dummy-admin")
+ public class DummyAdminCommand implements AdminCommand {
+ @Param(optional=false)
+ String foo;
+
+ @Param(name="bar", defaultValue="false", optional=true)
+ String foobar;
+
+ @Param(optional=false, defaultValue="there")
+ String hello;
+
+ @Param(optional=false, primary=true)
+ String world;
+
+ @Override
+ public void execute(AdminCommandContext context) {}
+ }
+
+ //mock-up SkipValidationCommand
+ public class SkipValidationCommand implements AdminCommand {
+ boolean skipParamValidation=true;
+ @Override
+ public void execute(AdminCommandContext context) {}
+ }
+
+
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/ConfigAttributeSetTest.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/ConfigAttributeSetTest.java
new file mode 100644
index 0000000..e499d52
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/ConfigAttributeSetTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.v3.common.HTMLActionReporter;
+import org.glassfish.grizzly.config.dom.NetworkListener;
+import org.glassfish.grizzly.config.dom.NetworkListeners;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.api.admin.*;
+import org.glassfish.tests.utils.ConfigApiTest;
+import org.glassfish.tests.utils.Utils;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.jvnet.hk2.config.ConfigListener;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.DomDocument;
+import org.jvnet.hk2.config.ObservableBean;
+import org.jvnet.hk2.config.Transactions;
+import org.jvnet.hk2.config.UnprocessedChangeEvents;
+
+import java.beans.PropertyChangeEvent;
+
+/**
+ * test the set command
+ * @author Jerome Dochez
+ */
+// Ignored temporarily because it fails to inject CommandRunnerImpl as ModulesRegistry is not available
+@Ignore
+public class ConfigAttributeSetTest extends ConfigApiTest implements ConfigListener {
+
+ ServiceLocator habitat = Utils.instance.getHabitat(this);
+ PropertyChangeEvent event = null;
+
+ public DomDocument getDocument(ServiceLocator habitat) {
+ return new TestDocument(habitat);
+ }
+
+ /**
+ * Returns the DomainTest file name without the .xml extension to load the test configuration
+ * from.
+ *
+ * @return the configuration file name
+ */
+ public String getFileName() {
+ return "DomainTest";
+ }
+
+ @Test
+ public void simpleAttributeSetTest() {
+
+ CommandRunnerImpl runner = habitat.getService(CommandRunnerImpl.class);
+ assertNotNull(runner);
+
+ // let's find our target
+ NetworkListener listener = null;
+ NetworkListeners service = habitat.getService(NetworkListeners.class);
+ for (NetworkListener l : service.getNetworkListener()) {
+ if ("http-listener-1".equals(l.getName())) {
+ listener = l;
+ break;
+ }
+ }
+ assertNotNull(listener);
+
+ // Let's register a listener
+ ObservableBean bean = (ObservableBean) ConfigSupport.getImpl(listener);
+ bean.addListener(this);
+
+ // parameters to the command
+ ParameterMap parameters = new ParameterMap();
+ parameters.set("value", "8090");
+ parameters.set("DEFAULT", "configs.config.server-config.http-service.http-listener.http-listener-1.port");
+
+ // execute the set command.
+ runner.getCommandInvocation("set", new HTMLActionReporter(), adminSubject()).parameters(parameters).execute();
+
+ // check the result.
+ String port = listener.getPort();
+ assertEquals(port, "8090");
+
+ // ensure events are delivered.
+ habitat.<Transactions>getService(Transactions.class).waitForDrain();
+
+ // finally
+ bean.removeListener(this);
+
+ // check we recevied the event
+ assertNotNull(event);
+ assertEquals("8080", event.getOldValue());
+ assertEquals("8090", event.getNewValue());
+ assertEquals("port", event.getPropertyName());
+
+ }
+
+ public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvents) {
+ assertEquals("Array size", propertyChangeEvents.length, 1 );
+ event = propertyChangeEvents[0];
+ return null;
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/CreateProfilerTest.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/CreateProfilerTest.java
new file mode 100644
index 0000000..70039c3
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/CreateProfilerTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import com.sun.enterprise.config.serverbeans.JavaConfig;
+import com.sun.enterprise.config.serverbeans.Profiler;
+import com.sun.logging.LogDomains;
+
+import java.beans.PropertyVetoException;
+import java.util.List;
+
+import org.glassfish.api.admin.AdminCommandContextImpl;
+import org.jvnet.hk2.config.types.Property;
+
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.admin.ParameterMap;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.Ignore;
+import static org.junit.Assert.*;
+import org.glassfish.api.ActionReport;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.tests.utils.Utils;
+import org.glassfish.tests.utils.ConfigApiTest;
+import org.jvnet.hk2.config.DomDocument;
+import org.jvnet.hk2.config.ConfigSupport;
+import org.jvnet.hk2.config.SingleConfigCode;
+import org.jvnet.hk2.config.TransactionFailure;
+
+/**
+ *
+ * @author Prashanth
+ */
+@Ignore
+public class CreateProfilerTest extends ConfigApiTest {
+ // Get Resources config bean
+ ServiceLocator habitat = Utils.instance.getHabitat(this);
+ private JavaConfig javaConfig = habitat.getService(JavaConfig.class);
+ private CreateProfiler command = null;
+ private ParameterMap parameters = new ParameterMap();
+ private AdminCommandContext context = null;
+ private CommandRunnerImpl cr = habitat.getService(CommandRunnerImpl.class);
+
+ @Override
+ public DomDocument getDocument(ServiceLocator habitat) {
+
+ return new TestDocument(habitat);
+ }
+
+ /**
+ * Returns the DomainTest file name without the .xml extension to load the test configuration
+ * from.
+ *
+ * @return the configuration file name
+ */
+ public String getFileName() {
+ return "DomainTest";
+ }
+
+ @Before
+ public void setUp() {
+ assertTrue(javaConfig!=null);
+
+ // Get an instance of the CreateProfiler command
+ command = habitat.getService(CreateProfiler.class);
+ assertTrue(command!=null);
+
+ context = new AdminCommandContextImpl(
+ LogDomains.getLogger(CreateProfilerTest.class, LogDomains.ADMIN_LOGGER),
+ habitat.<ActionReport>getService(ActionReport.class, "hk2-agent"));
+
+ }
+
+ @After
+ public void tearDown() throws TransactionFailure {
+ // Delete the created profiler
+ ConfigSupport.apply(new SingleConfigCode<JavaConfig>() {
+ public Object run(JavaConfig param) throws PropertyVetoException, TransactionFailure {
+ if (param.getProfiler() != null){
+ param.setProfiler(null);
+ }
+ return null;
+ }
+ }, javaConfig);
+
+ parameters = new ParameterMap();
+ }
+
+ /**
+ * Test of execute method, of class CreateProfiler.
+ * asadmin create-profiler --nativelibrarypath "myNativeLibraryPath"
+ * --enabled=true --classpath "myProfilerClasspath" testProfiler
+ */
+ @Test
+ public void testExecuteSuccess() {
+ // Set the options and operand to pass to the command
+ parameters.set("classpath", "myProfilerClasspath");
+ parameters.set("enabled", "true");
+ parameters.set("nativelibrarypath", "myNativeLibraryPath");
+ parameters.set("property","a=x:b=y:c=z");
+ parameters.set("DEFAULT", "testProfiler");
+
+
+ //Call CommandRunnerImpl.doCommand(..) to execute the command
+ cr.getCommandInvocation("create-profiler", context.getActionReport(), adminSubject()).parameters(parameters).execute(command);
+
+ // Check the exit code is SUCCESS
+ assertEquals(ActionReport.ExitCode.SUCCESS, context.getActionReport().getActionExitCode());
+
+ //Check that the profiler is created
+ boolean isCreated = false;
+ int propertyCount = 0;
+ Profiler profiler = javaConfig.getProfiler();
+ if (profiler.getName().equals("testProfiler")) {
+ assertEquals("myProfilerClasspath", profiler.getClasspath());
+ assertEquals("true", profiler.getEnabled());
+ assertEquals("myNativeLibraryPath", profiler.getNativeLibraryPath());
+ List<Property> properties = profiler.getProperty();
+ for (Property property:properties){
+ if (property.getName().equals("a")) assertEquals("x",property.getValue());
+ if (property.getName().equals("b")) assertEquals("y",property.getValue());
+ if (property.getName().equals("c")) assertEquals("z",property.getValue());
+ propertyCount++;
+ }
+ isCreated = true;
+ logger.fine("Profiler element myProfiler is created.");
+ }
+ assertTrue(isCreated);
+ assertEquals(propertyCount, 3);
+
+ // Check the exit code is SUCCESS
+ assertEquals(ActionReport.ExitCode.SUCCESS, context.getActionReport().getActionExitCode());
+
+ // Check the success message
+ //assertEquals("Command create-profiler executed successfully.", context.getActionReport().getMessage());
+ logger.fine("msg: " + context.getActionReport().getMessage());
+ }
+
+ /**
+ * Test of execute method, of class CreateProfiler with default values.
+ * asadmin create-profiler --nativelibrarypath "myNativeLibraryPath"
+ * --enabled=true --classpath "myProfilerClasspath" testProfiler
+ */
+ @Test
+ public void testExecuteSuccessDefaultValues() {
+ // Only pass the required option and operand
+ assertTrue(parameters.size() == 0);
+ parameters.set("DEFAULT", "myProfilerAllDefaults");
+
+
+ //Call CommandRunnerImpl.doCommand(..) to execute the command
+ cr.getCommandInvocation("create-profiler", context.getActionReport(), adminSubject()).parameters(parameters).execute(command);
+
+ // Check the exit code is SUCCESS
+ assertEquals(ActionReport.ExitCode.SUCCESS, context.getActionReport().getActionExitCode());
+
+ //Check that the resource was created
+ boolean isCreated = false;
+ Profiler profiler = javaConfig.getProfiler();
+ if (profiler.getName().equals("myProfilerAllDefaults")) {
+ //assertEquals("myProfilerClasspath", profiler.getClasspath());
+ assertEquals("true", profiler.getEnabled());
+ //assertEquals("nativelibrarypath", profiler.getNativeLibraryPath());
+ isCreated = true;
+ logger.fine("Profiler element myProfilerAllDefaults is created.");
+ }
+ assertTrue(isCreated);
+
+ // Check the success message
+ //assertEquals("Command create-profiler executed successfully.", context.getActionReport().getMessage());
+ logger.fine("msg: " + context.getActionReport().getMessage());
+ }
+
+ /**
+ * Test of execute method, creating a new when there is already one.
+ * asadmin create-profiler --nativelibrarypath "myNativeLibraryPath"
+ * --enabled=true --classpath "myProfilerClasspath" testProfiler
+ */
+ @Test
+ public void testExecuteSuccessUpdateExisting() {
+ assertTrue(parameters.size() == 0);
+ parameters.set("DEFAULT", "testProfiler");
+
+
+ //Call CommandRunnerImpl.doCommand(..) to execute the command
+ cr.getCommandInvocation("create-profiler", context.getActionReport(), adminSubject()).parameters(parameters).execute(command);
+
+ // Check the exit code is SUCCESS
+ assertEquals(ActionReport.ExitCode.SUCCESS, context.getActionReport().getActionExitCode());
+
+ parameters = new ParameterMap();
+
+ //Create another profiler, see if it overrides the existing one
+ parameters.set("DEFAULT", "testProfilerNew");
+
+
+ //Call CommandRunnerImpl.doCommand(..) to execute the command
+ cr.getCommandInvocation("create-profiler", context.getActionReport(), adminSubject()).parameters(parameters).execute(command);
+
+ // Check the exit code is SUCCESS
+ assertEquals(ActionReport.ExitCode.SUCCESS, context.getActionReport().getActionExitCode());
+
+ //Check that the resource was created
+ boolean isCreated = false;
+ Profiler profiler = javaConfig.getProfiler();
+ if (profiler.getName().equals("testProfilerNew")) {
+ //assertEquals("myProfilerClasspath", profiler.getClasspath());
+ assertEquals("true", profiler.getEnabled());
+ //assertEquals("nativelibrarypath", profiler.getNativeLibraryPath());
+ isCreated = true;
+ logger.fine("Profiler element testProfilerNew is created.");
+ }
+ assertTrue(isCreated);
+
+ // Check the success message
+ //assertEquals("Command create-profiler executed successfully.", context.getActionReport().getMessage());
+ logger.fine("msg: " + context.getActionReport().getMessage());
+ }
+
+ /**
+ * Test of execute method, of class CreateProfiler when enabled set to junk
+ * asadmin create-profiler --nativelibrarypath "myNativeLibraryPath"
+ * --enabled=true --classpath "myProfilerClasspath" testProfiler
+ */
+ @Test
+ public void testExecuteFailInvalidOptionEnabled() {
+ // Set invalid enabled option value: --enabled junk
+ //parameters = new ParameterMap();
+ assertTrue(parameters.size() == 0);
+ parameters.set("enabled", "junk");
+ parameters.set("DEFAULT", "myProfiler");
+
+ // Call CommandRunnerImpl.doCommand(..) to execute the command
+ cr.getCommandInvocation("create-profiler", context.getActionReport(), adminSubject()).parameters(parameters).execute(command);
+
+ // Check the exit code is Failure - test fails, need bug fix before uncommenting
+ assertEquals(ActionReport.ExitCode.FAILURE, context.getActionReport().getActionExitCode());
+
+ // Check the error message - test fails
+ assertEquals("Invalid parameter: enabled. This boolean option must be set (case insensitive) to true or false. Its value was set to junk",
+ context.getActionReport().getMessage());
+ }
+
+ /**
+ * Test of execute method, of class CreateProfiler when enabled has no value
+ * asadmin create-profiler --nativelibrarypath "myNativeLibraryPath"
+ * --enabled=true --classpath "myProfilerClasspath" testProfiler
+ */
+ @Test
+ public void testExecuteSuccessNoValueOptionEnabled() {
+ // Set enabled without a value: --enabled
+ assertTrue(parameters.size() == 0);
+ parameters.set("enabled", "");
+ parameters.set("DEFAULT", "testProfiler");
+
+ // Call CommandRunnerImpl.doCommand(..) to execute the command
+ cr.getCommandInvocation("create-profiler", context.getActionReport(), adminSubject()).parameters(parameters).execute(command);
+
+ //Check that the profiler is created
+ boolean isCreated = false;
+ Profiler profiler = javaConfig.getProfiler();
+ if (profiler.getName().equals("testProfiler")) {
+ assertEquals("true", profiler.getEnabled());
+ isCreated = true;
+ logger.fine("msg: " + context.getActionReport().getMessage());
+ }
+ assertTrue(isCreated);
+
+ // Check the exit code is SUCCESS
+ assertEquals(ActionReport.ExitCode.SUCCESS, context.getActionReport().getActionExitCode());
+
+ // Check the success message
+ //assertEquals("Command create-profiler executed successfully.", context.getActionReport().getMessage());
+ logger.fine("msg: " + context.getActionReport().getMessage());
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/PrivacyTest.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/PrivacyTest.java
new file mode 100644
index 0000000..9c0a936
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/PrivacyTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.junit.Test;
+import org.junit.Assert;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.tests.utils.Utils;
+
+/**
+ * Test the visibility annotation
+ */
+public class PrivacyTest {
+
+ @Test
+ public void privacyTests() {
+ AdminAdapter publicAdaper = new PublicAdminAdapter();
+ AdminAdapter privateAdapter = new PrivateAdminAdapter();
+ ServiceLocator habitat = Utils.getNewHabitat();
+ AdminCommand adminCommand = habitat.getService(AdminCommand.class, "simple-public-command");
+ Assert.assertTrue(publicAdaper.validatePrivacy(adminCommand));
+ Assert.assertFalse(privateAdapter.validatePrivacy(adminCommand));
+ adminCommand = habitat.getService(AdminCommand.class, "notannoated-public-command");
+ Assert.assertTrue(publicAdaper.validatePrivacy(adminCommand));
+ Assert.assertFalse(privateAdapter.validatePrivacy(adminCommand));
+ adminCommand = habitat.getService(AdminCommand.class, "simple-private-command");
+ Assert.assertFalse(publicAdaper.validatePrivacy(adminCommand));
+ Assert.assertTrue(privateAdapter.validatePrivacy(adminCommand));
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/SimplePrivateCommand.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/SimplePrivateCommand.java
new file mode 100644
index 0000000..1be8eea
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/SimplePrivateCommand.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.ActionReport;
+import org.glassfish.internal.api.Visibility;
+import org.glassfish.internal.api.Private;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * simple private command
+ */
+@Service(name="simple-private-command")
+@Visibility(Private.class)
+public class SimplePrivateCommand implements AdminCommand {
+
+ public void execute(AdminCommandContext context) {
+ context.getActionReport().setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/SimplePublicCommand.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/SimplePublicCommand.java
new file mode 100644
index 0000000..94955a9
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/SimplePublicCommand.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.internal.api.Visibility;
+import org.glassfish.internal.api.Public;
+import org.glassfish.api.admin.AdminCommand;
+import org.glassfish.api.admin.AdminCommandContext;
+import org.glassfish.api.ActionReport;
+
+/**
+ * simple public command
+ */
+@Service(name="simple-public-command")
+@Visibility(Public.class)
+public class SimplePublicCommand implements AdminCommand {
+ public void execute(AdminCommandContext context) {
+ context.getActionReport().setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/TestDocument.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/TestDocument.java
new file mode 100644
index 0000000..c8b38b1
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/TestDocument.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.admin;
+
+import org.jvnet.hk2.config.DomDocument;
+import org.jvnet.hk2.config.Dom;
+import org.jvnet.hk2.config.ConfigModel;
+import org.glassfish.config.support.GlassFishConfigBean;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.junit.Ignore;
+
+import javax.xml.stream.XMLStreamReader;
+
+/**
+ *
+ * This document will create the appropriate ConfigBean implementation but will
+ * not save the modified config tree.
+ *
+ * User: Jerome Dochez
+ */
+@Ignore
+public class TestDocument extends DomDocument<GlassFishConfigBean> {
+
+ public TestDocument(ServiceLocator habitat) {
+ super(habitat);
+ }
+
+ @Override
+ public Dom make(final ServiceLocator habitat, XMLStreamReader xmlStreamReader, GlassFishConfigBean dom, ConfigModel configModel) {
+ // by default, people get the translated view.
+ return new GlassFishConfigBean(habitat, this, dom, configModel, xmlStreamReader);
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/progress/.gitkeep_empty_dir b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/progress/.gitkeep_empty_dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/admin/progress/.gitkeep_empty_dir
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/common/PlainTextActionReporterTest.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/common/PlainTextActionReporterTest.java
new file mode 100644
index 0000000..99ebbf9
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/common/PlainTextActionReporterTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.sun.enterprise.v3.common;
+
+import org.glassfish.api.ActionReport;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author bnevins
+ */
+public class PlainTextActionReporterTest {
+
+ public PlainTextActionReporterTest() {
+ }
+
+ @Before
+ public void beforeTest() throws Exception {
+ System.out.println(
+ "\n-------------------------------------------------------------------------------");
+ }
+ @AfterClass
+ public static void afterTest() throws Exception {
+ System.out.println(
+ "-------------------------------------------------------------------------------");
+ }
+
+ @Test
+ public void failureTest() throws Exception {
+ ActionReport report = new PlainTextActionReporter();
+ report.setActionDescription("My Action Description");
+ report.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ ActionReport.MessagePart top = report.getTopMessagePart();
+ top.setMessage("FailureTest Message Here!!");
+ report.setFailureCause(new IndexOutOfBoundsException("Hi I am a phony Exception!!"));
+ report.writeReport(System.out);
+ }
+ @Test
+ public void babyTest() throws Exception {
+ ActionReport report = new PlainTextActionReporter();
+ report.setActionDescription("My Action Description");
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ ActionReport.MessagePart top = report.getTopMessagePart();
+ top.setMessage("BabyTest Message Here!!");
+ report.writeReport(System.out);
+ }
+
+ @Test
+ public void mamaTest() throws Exception {
+ ActionReport report = new PlainTextActionReporter();
+ report.setActionDescription("My Action Description");
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ ActionReport.MessagePart top = report.getTopMessagePart();
+ top.setMessage("Mama Test Top Message");
+ top.setChildrenType("Module");
+
+ for(int i = 0; i < 8; i++) {
+ ActionReport.MessagePart childPart = top.addChild();
+ childPart.setMessage("child" + i + " Message here");
+ childPart.addProperty("ChildKey" + i, "ChildValue" + i);
+ childPart.addProperty("AnotherChildKey" + i, "AnotherChildValue" + i);
+
+ ActionReport.MessagePart grandkids = childPart.addChild();
+ grandkids.setMessage("Grand Kids #" + i + " Top Message");
+ }
+ report.writeReport(System.out);
+ }
+
+ @Test
+ public void papaTest() throws Exception {
+ ActionReport report = new PlainTextActionReporter();
+ report.setActionDescription("My Action Description");
+ report.setActionExitCode(ActionReport.ExitCode.SUCCESS);
+ ActionReport.MessagePart top = report.getTopMessagePart();
+ top.setMessage("Papa Test Top Message");
+ top.setChildrenType("Module");
+
+ for(int i = 0; i < 8; i++) {
+ ActionReport.MessagePart childPart = top.addChild();
+ childPart.setMessage("child" + i + " Message here");
+ childPart.addProperty("ChildKey" + i, "ChildValue" + i);
+ childPart.addProperty("AnotherChildKey" + i, "AnotherChildValue" + i);
+
+ for(int j = 0; j < 3; j++) {
+ ActionReport.MessagePart grandkids = childPart.addChild();
+ grandkids.setMessage("Grand Kid#" + j + " from child#" + i + " Top Message");
+ grandkids.addProperty("Grand Kid#" + j + " from child#" + i + "key", "value");
+ }
+ }
+ report.writeReport(System.out);
+ }
+
+ @Test
+ public void aggregateTest() {
+ ActionReporter successfulRoot = new PlainTextActionReporter();
+ assert successfulRoot.hasSuccesses();
+ assert !successfulRoot.hasFailures();
+ assert !successfulRoot.hasWarnings();
+ ActionReport failedChild = successfulRoot.addSubActionsReport();
+ failedChild.setActionExitCode(ActionReport.ExitCode.FAILURE);
+ assert successfulRoot.hasSuccesses();
+ assert successfulRoot.hasFailures();
+ assert !successfulRoot.hasWarnings();
+ assert !failedChild.hasSuccesses();
+ assert !failedChild.hasWarnings();
+ assert failedChild.hasFailures();
+ ActionReport warningChild = failedChild.addSubActionsReport();
+ warningChild.setActionExitCode(ActionReport.ExitCode.WARNING);
+ assert successfulRoot.hasSuccesses();
+ assert successfulRoot.hasFailures();
+ assert successfulRoot.hasWarnings();
+ assert !failedChild.hasSuccesses();
+ assert failedChild.hasWarnings();
+ assert failedChild.hasFailures();
+ assert warningChild.hasWarnings();
+ assert !warningChild.hasSuccesses();
+ ActionReport successfulChild = warningChild.addSubActionsReport();
+ assert failedChild.hasSuccesses();
+ assert warningChild.hasSuccesses();
+ assert !warningChild.hasFailures();
+ StringBuilder sb = new StringBuilder();
+ successfulRoot.setMessage("sr");
+ successfulRoot.getCombinedMessages(successfulRoot, sb);
+ assertEquals("sr", sb.toString());
+ warningChild.setMessage("wc");
+ sb = new StringBuilder();
+ successfulRoot.getCombinedMessages(successfulRoot, sb);
+ assertEquals("sr\nwc", sb.toString());
+ failedChild.setMessage("fc");
+ sb = new StringBuilder();
+ successfulRoot.getCombinedMessages(successfulRoot, sb);
+ assertEquals("sr\nfc\nwc", sb.toString());
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/server/APIClassLoaderServiceImplTest.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/server/APIClassLoaderServiceImplTest.java
new file mode 100644
index 0000000..3b5d254
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/server/APIClassLoaderServiceImplTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+import static org.junit.Assert.assertEquals;
+
+import java.net.URL;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.sun.enterprise.module.ModuleLifecycleListener;
+import com.sun.enterprise.module.single.SingleModulesRegistry;
+
+public class APIClassLoaderServiceImplTest {
+ int loadClassCalls;
+ int getResourceCalls;
+
+ @Before
+ public void setUp() {
+ loadClassCalls = 0;
+ getResourceCalls = 0;
+ }
+
+ /**
+ * This test ensures that the ApiClassLoaderService will not attempt to load a class or find a resource after
+ * an initial negative result until a module is installed or update.
+ */
+ @Test
+ public void testBlackList() {
+ APIClassLoaderServiceImpl apiClassLoaderService = new APIClassLoaderServiceImpl();
+
+ // set up a fake ModulesRegistry to exercise ModulesRegistry lifecycle
+ // events
+ FakeClassLoader classLoader = new FakeClassLoader(getClass()
+ .getClassLoader());
+ FakeModulesRegistry mr = new FakeModulesRegistry(classLoader);
+
+ apiClassLoaderService.mr = mr;
+
+ assertEquals(0, mr.getLifecycleListeners().size());
+
+ apiClassLoaderService.postConstruct();
+
+ List<ModuleLifecycleListener> lifecycleListeners = mr
+ .getLifecycleListeners();
+
+ assertEquals(
+ "apiClassLoaderService should have registered a lifecycle listener",
+ 1, mr.getLifecycleListeners().size());
+
+ ModuleLifecycleListener lifecycleListener = lifecycleListeners
+ .iterator().next();
+
+ // assert that the classloader isn't called on to load the same bad
+ // class twice
+ assertEquals(0, loadClassCalls);
+
+ final String BAD_CLASSNAME = "BADCLASS";
+
+ try {
+ apiClassLoaderService.getAPIClassLoader().loadClass(BAD_CLASSNAME);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+
+ assertEquals("Classloader.loadClass not called at all", 1,
+ loadClassCalls);
+
+ try {
+ apiClassLoaderService.getAPIClassLoader().loadClass(BAD_CLASSNAME);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+
+ assertEquals(
+ "blacklist not honored, excessive call to classloader.load", 1,
+ loadClassCalls);
+
+ // try same thing with resources
+
+ assertEquals(0, getResourceCalls); // sanity
+
+ final String BAD_RESOURCE = "BADRESOURCE";
+
+ apiClassLoaderService.getAPIClassLoader().getResource(BAD_RESOURCE);
+
+ assertEquals("Classloader.findResource not called at all", 1,
+ getResourceCalls);
+
+ apiClassLoaderService.getAPIClassLoader().getResource(BAD_RESOURCE);
+
+ assertEquals(
+ "blacklist not honored, excessive call to classloader.getResource",
+ 1, getResourceCalls);
+
+ //
+ // Now signal that a new module has been loaded, clearing the blacklist
+ //
+
+ lifecycleListener.moduleInstalled(null);
+
+ apiClassLoaderService.getAPIClassLoader().getResource(BAD_RESOURCE);
+ assertEquals("blacklist did not clear after a module was installed", 2,
+ getResourceCalls);
+
+ try {
+ apiClassLoaderService.getAPIClassLoader().loadClass(BAD_CLASSNAME);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+
+ assertEquals("blacklist did not clear after a module was installed", 2,
+ loadClassCalls);
+
+ //
+ // Now signal that a new module has been updated, clearing the blacklist
+ //
+
+ lifecycleListener.moduleUpdated(null);
+
+ apiClassLoaderService.getAPIClassLoader().getResource(BAD_RESOURCE);
+ assertEquals("blacklist did not clear after a module was updated", 3,
+ getResourceCalls);
+
+ try {
+ apiClassLoaderService.getAPIClassLoader().loadClass(BAD_CLASSNAME);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+
+ assertEquals("blacklist did not clear after a module was updated", 3,
+ loadClassCalls);
+
+ }
+
+ class FakeModulesRegistry extends SingleModulesRegistry {
+ public FakeModulesRegistry(ClassLoader cl) {
+ super(cl);
+ }
+ }
+
+ class FakeClassLoader extends ClassLoader {
+ public FakeClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ @Override
+ public Class<?> loadClass(String arg0) throws ClassNotFoundException {
+ loadClassCalls++;
+ return super.loadClass(arg0);
+ }
+
+ @Override
+ protected URL findResource(String arg0) {
+ getResourceCalls++;
+ return super.findResource(arg0);
+ }
+
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/server/AppServerStartupTest.java b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/server/AppServerStartupTest.java
new file mode 100644
index 0000000..5dcf885
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/com/sun/enterprise/v3/server/AppServerStartupTest.java
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package com.sun.enterprise.v3.server;
+
+
+import com.sun.appserv.server.util.Version;
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.module.single.StaticModulesRegistry;
+import com.sun.enterprise.util.Result;
+
+import org.glassfish.api.FutureProvider;
+import org.glassfish.api.StartupRunLevel;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.hk2.api.Context;
+import org.glassfish.hk2.api.DynamicConfiguration;
+import org.glassfish.hk2.api.DynamicConfigurationService;
+import org.glassfish.hk2.api.PostConstruct;
+import org.glassfish.hk2.api.PreDestroy;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.api.ServiceLocatorFactory;
+import org.glassfish.hk2.runlevel.RunLevel;
+import org.glassfish.hk2.runlevel.RunLevelContext;
+import org.glassfish.hk2.runlevel.RunLevelController;
+import org.glassfish.hk2.runlevel.internal.AsyncRunLevelContext;
+import org.glassfish.hk2.runlevel.internal.RunLevelControllerImpl;
+import org.glassfish.hk2.utilities.AbstractActiveDescriptor;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.glassfish.hk2.utilities.DescriptorBuilder;
+import org.glassfish.internal.api.InitRunLevel;
+import org.glassfish.internal.api.PostStartupRunLevel;
+import org.glassfish.kernel.event.EventsImpl;
+import org.glassfish.main.core.apiexporter.APIExporterImpl;
+import org.glassfish.server.ServerEnvironmentImpl;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.jvnet.hk2.annotations.Service;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+
+/**
+ * AppServerStartup tests.
+ *
+ * @author Tom Beerbower
+ */
+public class AppServerStartupTest {
+
+ // ----- data members ----------------------------------------------------
+
+ /**
+ * The AppServerStartup instance to test.
+ */
+ private AppServerStartup as;
+
+ /**
+ * The test results.
+ */
+ private static Results results;
+
+
+ /**
+ * Map of exceptions to be thrown from the postConstruct.
+ */
+ private static Map<Class, RuntimeException> mapPostConstructExceptions = null;
+
+ /**
+ * List of {@link Future}s returned from {@link FutureProvider#getFutures()} by the Startup
+ * services during progression to the start up run level.
+ */
+ private static List<TestFuture> listFutures = null;
+
+ private ServiceLocator testLocator;
+
+
+ // ----- test initialization ---------------------------------------------
+
+ private void initialize(ServiceLocator testLocator) {
+ DynamicConfigurationService dcs = testLocator.getService(DynamicConfigurationService.class);
+ DynamicConfiguration config = dcs.createDynamicConfiguration();
+
+ config.addActiveDescriptor(BuilderHelper.createConstantDescriptor(new TestSystemTasks()));
+
+ // These are services that would normally be started by hk2 core
+ config.addActiveDescriptor(AppServerStartup.AppInstanceListener.class);
+
+ AbstractActiveDescriptor<?> descriptor = BuilderHelper.createConstantDescriptor(new TestModulesRegistry());
+ descriptor.addContractType(ModulesRegistry.class);
+ config.addActiveDescriptor(descriptor);
+
+ descriptor = BuilderHelper.createConstantDescriptor(new ExecutorServiceFactory().provide());
+ descriptor.addContractType(ExecutorService.class);
+ config.addActiveDescriptor(descriptor);
+
+ config.addActiveDescriptor(BuilderHelper.createConstantDescriptor(new ServerEnvironmentImpl()));
+ config.addActiveDescriptor(BuilderHelper.createConstantDescriptor(new EventsImpl()));
+ config.addActiveDescriptor(BuilderHelper.createConstantDescriptor(new Version()));
+ config.addActiveDescriptor(BuilderHelper.createConstantDescriptor(new StartupContext()));
+
+ config.bind(BuilderHelper.link(RunLevelControllerImpl.class).to(RunLevelController.class).build());
+
+ config.addUnbindFilter(BuilderHelper.createContractFilter(RunLevelContext.class.getName()));
+ config.bind(BuilderHelper.link(RunLevelContext.class).to(Context.class).in(Singleton.class).build());
+
+ config.addUnbindFilter(BuilderHelper.createContractFilter(AsyncRunLevelContext.class.getName()));
+ config.bind(BuilderHelper.link(AsyncRunLevelContext.class).in(Singleton.class).build());
+
+ config.bind(BuilderHelper.link(AppServerStartup.class).build());
+
+ descriptor = BuilderHelper.createConstantDescriptor(testLocator);
+ descriptor.addContractType(ServiceLocator.class);
+ config.addActiveDescriptor(descriptor);
+
+ bindService(config, TestInitRunLevelService.class);
+ bindService(config, TestStartupService.class);
+ bindService(config, TestStartupRunLevelService.class);
+ bindService(config, TestPostStartupRunLevelService.class);
+
+ bindService(config, CommonClassLoaderServiceImpl.class);
+ bindService(config, APIClassLoaderServiceImpl.class);
+
+ bindService(config, APIExporterImpl.class);
+ config.commit();
+ }
+
+ private void bindService(DynamicConfiguration configurator, Class<?> service) {
+ final DescriptorBuilder descriptorBuilder = BuilderHelper.link(service);
+
+ final RunLevel rla = service.getAnnotation(RunLevel.class);
+ if (rla != null) {
+ descriptorBuilder.to(RunLevel.class).
+ has(RunLevel.RUNLEVEL_VAL_META_TAG, Collections.singletonList(((Integer) rla.value()).toString())).
+ has(RunLevel.RUNLEVEL_MODE_META_TAG, Collections.singletonList(((Integer) rla.mode()).toString()));
+
+ descriptorBuilder.in(RunLevel.class);
+ }
+ Class clazz = service;
+ while (clazz != null) {
+ Class<?>[] interfaces = clazz.getInterfaces();
+ for (int j = 0; j < interfaces.length; j++) {
+ descriptorBuilder.to(interfaces[j]);
+ }
+ clazz = clazz.getSuperclass();
+ }
+
+ final Named named = service.getAnnotation(Named.class);
+ if (named != null) {
+ descriptorBuilder.named(named.value());
+ }
+
+ configurator.bind(descriptorBuilder.build());
+ }
+
+
+ /**
+ * Reset the results prior to each test.
+ */
+ @Before
+ public void beforeTest() {
+ testLocator = ServiceLocatorFactory.getInstance().create("AppServerStartupTest");
+ initialize(testLocator);
+
+ as = testLocator.getService(AppServerStartup.class);
+ Assert.assertNotNull(as);
+
+ mapPostConstructExceptions = new HashMap<Class, RuntimeException>();
+ listFutures = new LinkedList<TestFuture>();
+ results = new Results(as.runLevelController);
+
+ as.events.register(results);
+ }
+
+ /**
+ * Ensure that things are stopped after the test... if not then call stop.
+ */
+ @After
+ public void afterTest() {
+ if (as != null) {
+ if (as.runLevelController.getCurrentRunLevel() > 0) {
+ // force a stop to ensure that the services are released
+ as.env.setStatus(ServerEnvironment.Status.started);
+ as.stop();
+ }
+
+ as.events.unregister(results);
+ }
+ results = null;
+ listFutures = null;
+ mapPostConstructExceptions = null;
+
+ ServiceLocatorFactory.getInstance().destroy(testLocator);
+ testLocator = null;
+ }
+
+ // ----- tests -----------------------------------------------------------
+
+ /**
+ * Call the {@link AppServerStartup#run} method and make sure that
+ * the run level services are constructed and destroyed at the proper
+ * run levels.
+ */
+ //Ignored these tests and raised an issue(#22374) to track.
+ @Ignore
+ @Test
+ public void testRunLevelServices() {
+ // create the list of Futures returned from TestStartupService
+ listFutures.add(new TestFuture());
+ listFutures.add(new TestFuture());
+ listFutures.add(new TestFuture());
+
+ testRunAppServerStartup();
+
+ Assert.assertTrue(as.env.getStatus() == ServerEnvironment.Status.started);
+
+ Assert.assertEquals(2, results.getListEvents().size());
+ Assert.assertEquals(EventTypes.SERVER_STARTUP, results.getListEvents().get(0));
+ Assert.assertEquals(EventTypes.SERVER_READY, results.getListEvents().get(1));
+
+ // assert that the run level services have been constructed
+ Assert.assertTrue(results.isConstructed(TestInitRunLevelService.class, InitRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestStartupService.class, StartupRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestStartupRunLevelService.class, StartupRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestPostStartupRunLevelService.class, PostStartupRunLevel.VAL));
+
+ as.stop();
+
+ Assert.assertFalse(as.env.getStatus() == ServerEnvironment.Status.started);
+
+ Assert.assertEquals(4, results.getListEvents().size());
+ Assert.assertEquals(EventTypes.PREPARE_SHUTDOWN, results.getListEvents().get(2));
+ Assert.assertEquals(EventTypes.SERVER_SHUTDOWN, results.getListEvents().get(3));
+
+ // assert that the run level services have been destroyed
+ Assert.assertTrue(results.isDestroyed(TestPostStartupRunLevelService.class, PostStartupRunLevel.VAL));
+ Assert.assertTrue(results.isDestroyed(TestStartupService.class, StartupRunLevel.VAL));
+ Assert.assertTrue(results.isDestroyed(TestStartupRunLevelService.class, StartupRunLevel.VAL));
+ Assert.assertTrue(results.isDestroyed(TestInitRunLevelService.class, InitRunLevel.VAL));
+ }
+
+ /**
+ * Test the {@link AppServerStartup#run} method with an exception thrown from an init
+ * service that should cause a failure during init. Make sure that the init run level
+ * services are constructed at the proper run levels.
+ */
+ @Ignore
+ @Test
+ public void testRunLevelServicesWithInitException() {
+ testRunLevelServicesWithException(TestInitRunLevelService.class);
+
+ // make sure that the server has not been started
+ Assert.assertFalse(as.env.getStatus() == ServerEnvironment.Status.started);
+
+ // assert that the run level services have been constructed
+ Assert.assertTrue(results.isConstructed(TestInitRunLevelService.class, InitRunLevel.VAL));
+ // assert that startup & post-startup services are not constructed since the failure occurs during init
+ Assert.assertFalse(results.isConstructed(TestStartupService.class));
+ Assert.assertFalse(results.isConstructed(TestStartupRunLevelService.class));
+ Assert.assertFalse(results.isConstructed(TestPostStartupRunLevelService.class));
+ }
+
+ /**
+ * Test the {@link AppServerStartup#run} method with an exception thrown from a startup
+ * service that should cause a failure during startup. Make sure that the init and
+ * startup run level services are constructed at the proper run levels.
+ */
+ @Ignore
+ @Test
+ public void testRunLevelServicesWithStartupException() {
+ testRunLevelServicesWithException(TestStartupService.class);
+
+ // make sure that the server has not been started
+ Assert.assertFalse(as.env.getStatus() == ServerEnvironment.Status.started);
+
+ Assert.assertTrue(results.getListEvents().contains(EventTypes.SERVER_SHUTDOWN));
+
+ // assert that the run level services have been constructed
+ Assert.assertTrue(results.isConstructed(TestInitRunLevelService.class, InitRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestStartupService.class, StartupRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestStartupRunLevelService.class, StartupRunLevel.VAL));
+ // assert that the post-startup service is not constructed since shutdown occurs during startup
+ Assert.assertFalse(results.isConstructed(TestPostStartupRunLevelService.class));
+ }
+
+ /**
+ * Test the {@link AppServerStartup#run} method with an exception thrown from a
+ * post-startup service that should cause a failure during post-startup. Make sure
+ * that the run level services are constructed at the proper run levels.
+ */
+ @Ignore
+ @Test
+ public void testRunLevelServicesWithPostStartupException() {
+ testRunLevelServicesWithException(TestPostStartupRunLevelService.class);
+
+ // assert that the run level services have been constructed
+ Assert.assertTrue(results.isConstructed(TestInitRunLevelService.class, InitRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestStartupService.class, StartupRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestStartupRunLevelService.class, StartupRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestPostStartupRunLevelService.class, PostStartupRunLevel.VAL));
+ }
+
+ /**
+ * Test the {@link AppServerStartup#run} method with an exception thrown from a
+ * {@link Future} should cause a failed result during startup. Make sure that the init
+ * and startup run level services are constructed at the proper run levels. Also ensure
+ * that the failed {@link Future} causes a shutdown.
+ */
+ @Ignore
+ @Test
+ public void testRunLevelServicesWithFuturesException() {
+
+ // create the list of Futures returned from TestStartupService
+ listFutures.add(new TestFuture());
+ listFutures.add(new TestFuture(new Exception("Exception from Future.")));
+ listFutures.add(new TestFuture());
+
+ testRunAppServerStartup();
+
+ // make sure that the server has not been started
+ Assert.assertFalse(as.env.getStatus() == ServerEnvironment.Status.started);
+
+ Assert.assertTrue(results.getListEvents().contains(EventTypes.SERVER_SHUTDOWN));
+
+ // assert that the run level services have been constructed
+ Assert.assertTrue(results.isConstructed(TestInitRunLevelService.class, InitRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestStartupService.class, StartupRunLevel.VAL));
+ Assert.assertTrue(results.isConstructed(TestStartupRunLevelService.class, StartupRunLevel.VAL));
+ // assert that the post-startup service is not constructed since shutdown occurs during startup
+ Assert.assertFalse(results.isConstructed(TestPostStartupRunLevelService.class));
+ }
+
+
+ // ----- helper methods --------------------------------------------------
+
+ /**
+ * Helper method to run the app server after asserting that the results are clean.
+ */
+ private void testRunAppServerStartup() {
+ // assert that we have clean results to start
+ Assert.assertFalse(results.isConstructed(TestInitRunLevelService.class));
+ Assert.assertFalse(results.isConstructed(TestStartupService.class));
+ Assert.assertFalse(results.isConstructed(TestStartupRunLevelService.class));
+ Assert.assertFalse(results.isConstructed(TestPostStartupRunLevelService.class));
+
+ as.run();
+ }
+
+ /**
+ * Helper method to call {@link AppServerStartup#run()}. Sets up an exception
+ * to be thrown from {@link PostConstruct#postConstruct()} of the given class.
+ *
+ * @param badServiceClass the service class that the exception will be thrown from
+ */
+ @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+ private void testRunLevelServicesWithException(Class badServiceClass) {
+ // set an exception to be thrown from TestStartupService.postConstruct()
+ mapPostConstructExceptions.put(badServiceClass,
+ new RuntimeException("Exception from " + badServiceClass.getSimpleName() + ".postConstruct"));
+
+ // create the list of Futures returned from TestStartupService
+ listFutures.add(new TestFuture());
+
+ testRunAppServerStartup();
+ }
+
+
+ // ----- Results inner class ---------------------------------------------
+
+ /**
+ * Test results
+ */
+ private static class Results implements EventListener {
+ /**
+ * Map of constructed run level services to run levels.
+ */
+ private Map<Class, Integer> mapConstructedLevels = new HashMap<Class, Integer>();
+
+ /**
+ * Map of destroyed run level services to run levels.
+ */
+ private Map<Class, Integer> mapDestroyedLevels = new HashMap<Class, Integer>();
+
+ /**
+ * List of server events.
+ */
+ private List<EventTypes> listEvents = new LinkedList<EventTypes>();
+
+ /**
+ * The run level service.
+ */
+ private RunLevelController rls;
+
+ public Results(RunLevelController rls) {
+ this.rls = rls;
+ }
+
+ public void recordConstruction(Class cl) {
+ mapConstructedLevels.put(cl, rls.getCurrentProceeding().getProposedLevel());
+ }
+
+ public void recordDestruction(Class cl) {
+ mapDestroyedLevels.put(cl, rls.getCurrentRunLevel() + 1);
+ }
+
+ public boolean isConstructed(Class cl) {
+ return mapConstructedLevels.keySet().contains(cl);
+ }
+
+ public boolean isConstructed(Class cl, Integer runLevel) {
+ Integer recLevel = mapConstructedLevels.get(cl);
+ return recLevel != null && recLevel.equals(runLevel);
+ }
+
+ public boolean isDestroyed(Class cl) {
+ return mapDestroyedLevels.keySet().contains(cl);
+ }
+
+ public boolean isDestroyed(Class cl, Integer runLevel) {
+ Integer recLevel = mapDestroyedLevels.get(cl);
+ return recLevel != null && recLevel.equals(runLevel);
+ }
+
+ public List<EventTypes> getListEvents() {
+ return listEvents;
+ }
+
+ @Override
+ public void event(Event event) {
+ listEvents.add(event.type());
+ }
+ }
+
+
+ // ----- test services inner classes -------------------------------------
+
+ /**
+ * Abstract service that will update the test results from
+ * {@link PostConstruct#postConstruct()}.
+ */
+ public static abstract class TestService implements PostConstruct, PreDestroy {
+ @Override
+ public void postConstruct() {
+ AppServerStartupTest.results.recordConstruction(this.getClass());
+ if (mapPostConstructExceptions != null) {
+ RuntimeException ex = mapPostConstructExceptions.get(getClass());
+ if (ex != null) {
+ throw ex;
+ }
+ }
+ }
+
+ @Override
+ public void preDestroy() {
+ AppServerStartupTest.results.recordDestruction(this.getClass());
+ }
+ }
+
+ /**
+ * Init service annotated with the new style {@link InitRunLevel} annotation.
+ */
+ @Service
+ @RunLevel(InitRunLevel.VAL)
+ public static class TestInitRunLevelService extends TestService {
+ }
+
+ /**
+ * Startup service that implements the old style Startup interface.
+ */
+ @RunLevel(StartupRunLevel.VAL)
+ @Service
+ public static class TestStartupService extends TestService implements FutureProvider {
+ // Make sure the other one starts first
+ @SuppressWarnings("unused")
+ @Inject
+ private TestStartupRunLevelService dependency;
+
+ @Override
+ public List getFutures() {
+ return listFutures;
+ }
+ }
+
+ /**
+ * Startup service annotated with the new style {@link StartupRunLevel} annotation.
+ */
+ @Service
+ @RunLevel(StartupRunLevel.VAL)
+ public static class TestStartupRunLevelService extends TestService {
+ }
+
+ /**
+ * Post-startup service annotated with the new style {@link PostStartupRunLevel} annotation.
+ */
+ @Service
+ @RunLevel(PostStartupRunLevel.VAL)
+ public static class TestPostStartupRunLevelService extends TestService {
+ }
+
+
+ // ----- TestSystemTasks inner classes -----------------------------------
+
+ /**
+ * Test {@link SystemTasks} implementation.
+ */
+ public static class TestSystemTasks implements SystemTasks {
+ @Override
+ public void writePidFile() {
+ // do nothing.
+ }
+ }
+
+
+ // ----- TestModulesRegistry inner classes -------------------------------
+
+ /**
+ * Test {@link ModulesRegistry} implementation.
+ */
+ public static class TestModulesRegistry extends StaticModulesRegistry {
+
+ public TestModulesRegistry() {
+ super(TestModulesRegistry.class.getClassLoader());
+ }
+ }
+
+
+ // ----- TestFuture inner classes ----------------------------------------
+
+ /**
+ * Future implementation used for test Startup implementations that
+ * also implement {@link FutureProvider}.
+ */
+ public static class TestFuture implements Future<Result<Thread>> {
+
+ private boolean canceled = false;
+ private boolean done = false;
+ private Exception resultException = null;
+
+ public TestFuture() {
+ }
+
+ public TestFuture(Exception resultException) {
+ this.resultException = resultException;
+ }
+
+ @Override
+ public boolean cancel(boolean b) {
+ if (done) {
+ return false;
+ }
+ canceled = done = true;
+ return true;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return canceled;
+ }
+
+ @Override
+ public boolean isDone() {
+ return done;
+ }
+
+ @Override
+ public Result<Thread> get() throws InterruptedException, ExecutionException {
+
+ Result<Thread> result = resultException == null ?
+ new Result<Thread>(Thread.currentThread()) :
+ new Result<Thread>(resultException);
+ done = true;
+
+ return result;
+ }
+
+ @Override
+ public Result<Thread> get(long l, TimeUnit timeUnit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return get();
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/admin/CommandRunnerTest.java b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/admin/CommandRunnerTest.java
new file mode 100644
index 0000000..2e964db
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/admin/CommandRunnerTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.tests.kernel.admin;
+
+import com.sun.enterprise.config.serverbeans.Domain;
+import com.sun.enterprise.module.ModulesRegistry;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+import com.sun.enterprise.module.single.SingleModulesRegistry;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import junit.framework.Assert;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.CommandRunner;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import javax.inject.Inject;
+import org.glassfish.internal.api.InternalSystemAdministrator;
+import org.jvnet.hk2.testing.junit.HK2Runner;
+
+/**
+ * Test the command runner implementation.
+ *
+ * @author Jerome Dochez
+ */
+@Ignore
+public class CommandRunnerTest extends HK2Runner {
+
+ @Inject
+ CommandRunner commandRunner;
+
+ @Inject
+ InternalSystemAdministrator kernelIdentity;
+
+ @BeforeClass
+ public void setup() {
+
+ /*
+ * The CommandRunnerImpl now injects Domain but these tests do not
+ * exercise the code path that requires the domain. So register a
+ * dummy Domain instance with the habitat so injection will work.
+ */
+ ServiceLocatorUtilities.addOneDescriptor(testLocator,
+ BuilderHelper.createConstantDescriptor(simpleDomain(), null, Domain.class));
+ ServiceLocatorUtilities.addOneConstant(testLocator, new StartupContext());
+ ServiceLocatorUtilities.addOneDescriptor(testLocator,
+ BuilderHelper.createConstantDescriptor(new SingleModulesRegistry(CommandRunnerTest.class.getClassLoader()),
+ null, ModulesRegistry.class));
+ }
+
+ private static Domain simpleDomain() {
+ InvocationHandler handler = new InvocationHandler() {
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ throw new UnsupportedOperationException("Feature-free dummy implementation for injection only");
+ }
+ };
+ Domain d = (Domain) Proxy.newProxyInstance(Domain.class.getClassLoader(),
+ new Class[] { Domain.class },
+ handler);
+ return d;
+ }
+
+ @Test
+ public void tryOut() {
+ Assert.assertTrue(commandRunner!=null);
+ try {
+ ActionReport report = commandRunner.getActionReport("plain");
+ CommandRunner.CommandInvocation inv = commandRunner.getCommandInvocation("list-contracts", report, kernelIdentity.getSubject());
+ inv.execute();
+ System.out.println(report.getTopMessagePart().getMessage());
+ for (ActionReport.MessagePart child : report.getTopMessagePart().getChildren()) {
+ System.out.println(child.getMessage());
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/deployment/EventsTest.java b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/deployment/EventsTest.java
new file mode 100644
index 0000000..9fc18c8
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/deployment/EventsTest.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.tests.kernel.deployment;
+
+import org.junit.*;
+import org.glassfish.api.event.Events;
+import org.glassfish.api.event.EventListener;
+import org.glassfish.api.event.EventTypes;
+import org.glassfish.api.deployment.DeployCommandParameters;
+import org.glassfish.api.deployment.UndeployCommandParameters;
+import org.glassfish.api.ActionReport;
+import org.glassfish.api.admin.ServerEnvironment;
+import org.glassfish.tests.utils.ConfigApiTest;
+import org.glassfish.hk2.api.ActiveDescriptor;
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.hk2.utilities.BuilderHelper;
+import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
+import org.glassfish.internal.deployment.Deployment;
+import org.glassfish.internal.deployment.ExtendedDeploymentContext;
+import org.glassfish.config.support.GlassFishDocument;
+import org.jvnet.hk2.config.DomDocument;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.Logger;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.sun.enterprise.config.serverbeans.Server;
+import com.sun.enterprise.module.bootstrap.StartupContext;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: dochez
+ * Date: Mar 12, 2009
+ * Time: 9:26:57 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class EventsTest extends ConfigApiTest {
+
+ static ServiceLocator habitat;
+ static File application;
+ static List<EventListener.Event> allEvents = new ArrayList<EventListener.Event>();
+ static private EventListener listener = new EventListener() {
+ public void event(Event event) {
+ //System.out.println("Received event " + event.name());
+ allEvents.add(event);
+ }
+ };
+
+ public String getFileName() {
+ return "DomainTest";
+ }
+
+ @Override
+ public DomDocument getDocument(ServiceLocator habitat) {
+ DomDocument doc = habitat.getService(GlassFishDocument.class);
+ if (doc==null) {
+ return new GlassFishDocument(habitat, Executors.newCachedThreadPool(new ThreadFactory() {
+
+ public Thread newThread(Runnable r) {
+ Thread t = Executors.defaultThreadFactory().newThread(r);
+ t.setDaemon(true);
+ return t;
+ }
+
+ }));
+ }
+ return doc;
+ }
+
+ @Before
+ public void setup() throws IOException {
+
+ // cludge to run only once yet not depend on a static method.
+ if (habitat!=null) {
+ return;
+ }
+ habitat = super.getHabitat();
+
+ Server server = habitat.getService(Server.class, "server");
+ ActiveDescriptor<Server> descriptor = BuilderHelper.createConstantDescriptor(server,
+ ServerEnvironment.DEFAULT_INSTANCE_NAME, Server.class);
+ ServiceLocatorUtilities.addOneDescriptor(habitat, descriptor);
+
+ try {
+ application = File.createTempFile("kerneltest", "tmp");
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw e;
+
+ }
+
+ application.delete();
+ application.mkdirs();
+
+ Events events = habitat.getService(Events.class);
+ events.register(listener);
+ }
+
+ @AfterClass
+ public static void tearDown() {
+ if (application != null) {
+ application.delete();
+ }
+ }
+
+ public static List<EventTypes> getSingletonModuleSuccessfullDeploymentEvents() {
+ ArrayList<EventTypes> events = new ArrayList<EventTypes>();
+ events.add(Deployment.MODULE_PREPARED);
+ events.add(Deployment.MODULE_LOADED);
+ events.add(Deployment.MODULE_STARTED);
+ events.add(Deployment.APPLICATION_PREPARED);
+ events.add(Deployment.APPLICATION_LOADED);
+ events.add(Deployment.APPLICATION_STARTED);
+ return events;
+ }
+
+ public static List<EventTypes> getSingletonModuleSuccessfullUndeploymentEvents() {
+ ArrayList<EventTypes> events = new ArrayList<EventTypes>();
+ events.add(Deployment.MODULE_STOPPED);
+ events.add(Deployment.MODULE_UNLOADED);
+ events.add(Deployment.MODULE_CLEANED);
+ events.add(Deployment.APPLICATION_STOPPED);
+ events.add(Deployment.APPLICATION_UNLOADED);
+ events.add(Deployment.APPLICATION_CLEANED);
+ return events;
+ }
+
+ public static List<EventTypes> asynchonousEvents() {
+ ArrayList<EventTypes> events = new ArrayList<EventTypes>();
+ events.add(Deployment.DEPLOYMENT_START);
+ events.add(Deployment.DEPLOYMENT_SUCCESS);
+ events.add(Deployment.UNDEPLOYMENT_START);
+ events.add(Deployment.UNDEPLOYMENT_SUCCESS);
+ events.add(Deployment.UNDEPLOYMENT_FAILURE);
+ return events;
+ }
+
+ @Test
+ public void deployUndeployTest() throws Exception {
+
+ final List<EventTypes> myTestEvents = getSingletonModuleSuccessfullDeploymentEvents();
+ Events events = habitat.getService(Events.class);
+ EventListener listener = new EventListener() {
+ public void event(Event event) {
+ if (myTestEvents.contains(event.type())) {
+ myTestEvents.remove(event.type());
+ }
+ }
+ };
+ events.register(listener);
+ Deployment deployment = habitat.getService(Deployment.class);
+ DeployCommandParameters params = new DeployCommandParameters(application);
+ params.name = "fakeApplication";
+ params.target = "server";
+ ActionReport report = habitat.getService(ActionReport.class, "hk2-agent");
+ ExtendedDeploymentContext dc = deployment.getBuilder(Logger.getAnonymousLogger(), params, report).source(application).build();
+ deployment.deploy(dc);
+ events.unregister(listener);
+ for (EventTypes et : myTestEvents) {
+ System.out.println("An expected event of type " + et.type() + " was not received");
+ }
+
+ try {
+ final List<EventTypes> myTestEvents2 = getSingletonModuleSuccessfullUndeploymentEvents();
+ EventListener listener2 = new EventListener() {
+ public void event(Event event) {
+ if (myTestEvents2.contains(event.type())) {
+ myTestEvents2.remove(event.type());
+ }
+ }
+ };
+ events.register(listener2);
+ UndeployCommandParameters params2 = new UndeployCommandParameters("fakeApplication");
+ params2.target = "server";
+ ActionReport report2 = habitat.getService(ActionReport.class, "hk2-agent");
+ ExtendedDeploymentContext dc2 = deployment.getBuilder(Logger.getAnonymousLogger(), params2, report2).source(application).build();
+ deployment.undeploy("fakeApplication", dc2);
+ events.unregister(listener2);
+ for (EventTypes et : myTestEvents2) {
+ System.out.println("An expected event of type " + et.type() + " was not received");
+ }
+ } catch(Throwable t) {
+ t.printStackTrace();
+ }
+
+ }
+
+ @Test
+ public void badUndeployTest() throws Exception {
+ Deployment deployment = habitat.getService(Deployment.class);
+ UndeployCommandParameters params = new UndeployCommandParameters("notavalidname");
+ params.target = "server";
+ ActionReport report = habitat.getService(ActionReport.class, "hk2-agent");
+ ExtendedDeploymentContext dc = deployment.getBuilder(Logger.getAnonymousLogger(), params, report).source(application).build();
+ deployment.undeploy("notavalidname", dc);
+ Assert.assertEquals(report.getActionExitCode(), ActionReport.ExitCode.FAILURE);
+ }
+
+ @Test
+ @Ignore
+ public void asynchronousEvents() {
+ List<EventTypes> asyncEvents = asynchonousEvents();
+ Iterator<EventTypes> itr = asyncEvents.iterator();
+ while (itr.hasNext()) {
+ EventTypes et = itr.next();
+ for (EventListener.Event evt : allEvents) {
+ if (evt.is(et)) {
+ itr.remove();
+ }
+ }
+ }
+ for (EventTypes et : asyncEvents) {
+ System.out.println("Asynchronous event " + et.type() + " was not received");
+ }
+ Assert.assertTrue(asyncEvents.size()==0);
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/deployment/container/FakeContainer.java b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/deployment/container/FakeContainer.java
new file mode 100644
index 0000000..7f5fe4d
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/deployment/container/FakeContainer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.tests.kernel.deployment.container;
+
+import org.glassfish.api.container.Container;
+import org.glassfish.api.deployment.Deployer;
+import org.glassfish.internal.deployment.GenericDeployer;
+import org.jvnet.hk2.annotations.Service;
+
+/**
+ * Fake container for testing purposes
+ *
+ * @author Jerome Dochez
+ */
+@Service(name="FakeContainer")
+public class FakeContainer implements Container {
+
+ public Class<? extends Deployer> getDeployer() {
+ return GenericDeployer.class;
+ }
+
+ public String getName() {
+ return "Fake";
+ }
+}
diff --git a/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/deployment/container/FakeSniffer.java b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/deployment/container/FakeSniffer.java
new file mode 100644
index 0000000..1509d5e
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/deployment/container/FakeSniffer.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.tests.kernel.deployment.container;
+
+import org.jvnet.hk2.annotations.Service;
+import org.glassfish.api.container.Sniffer;
+import org.glassfish.api.deployment.archive.ReadableArchive;
+import org.glassfish.api.deployment.archive.ArchiveType;
+import org.glassfish.api.deployment.DeploymentContext;
+
+import java.lang.annotation.Annotation;
+import java.util.logging.Logger;
+import java.util.Map;
+import java.io.IOException;
+
+import com.sun.enterprise.module.Module;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: dochez
+ * Date: Mar 12, 2009
+ * Time: 9:20:37 AM
+ * To change this template use File | Settings | File Templates.
+ */
+@Service
+public class FakeSniffer implements Sniffer {
+
+ public boolean handles(ReadableArchive source) {
+ // I handle everything
+ return true;
+ }
+
+ public boolean handles(DeploymentContext context) {
+ // I handle everything
+ return true;
+ }
+
+ public String[] getURLPatterns() {
+ return new String[0]; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Class<? extends Annotation>[] getAnnotationTypes() {
+ return null;
+ }
+
+ public String[] getAnnotationNames(DeploymentContext context) {
+ return null;
+ }
+
+ public String getModuleType() {
+ return "fake";
+ }
+
+ public Module[] setup(String containerHome, Logger logger) throws IOException {
+ return null;
+ }
+
+ public void tearDown() {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public String[] getContainersNames() {
+ return new String[] { "FakeContainer" };
+ }
+
+ public boolean isUserVisible() {
+ return false;
+ }
+
+ public boolean isJavaEE() {
+ return false;
+ }
+
+ public Map<String, String> getDeploymentConfigurations(ReadableArchive source) throws IOException {
+ return null;
+ }
+
+ public String[] getIncompatibleSnifferTypes() {
+ return new String[0];
+ }
+
+ public boolean supportsArchiveType(ArchiveType archiveType) {
+ return true;
+ }
+
+}
diff --git a/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/embedded/.gitkeep_empty_dir b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/embedded/.gitkeep_empty_dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nucleus/core/kernel/src/test/java/org/glassfish/tests/kernel/embedded/.gitkeep_empty_dir
diff --git a/nucleus/core/kernel/src/test/resources/DomainTest.xml b/nucleus/core/kernel/src/test/resources/DomainTest.xml
new file mode 100644
index 0000000..cfd9c01
--- /dev/null
+++ b/nucleus/core/kernel/src/test/resources/DomainTest.xml
@@ -0,0 +1,151 @@
+<!--
+
+ Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v. 2.0, which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ This Source Code may also be made available under the following Secondary
+ Licenses when the conditions for such availability set forth in the
+ Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ version 2 with the GNU Classpath Exception, which is available at
+ https://www.gnu.org/software/classpath/license.html.
+
+ SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<domain log-root="${com.sun.aas.instanceRoot}/logs" application-root="${com.sun.aas.instanceRoot}/applications">
+ <applications>
+ </applications>
+ <resources/>
+ <configs>
+ <config name="server-config">
+ <admin-service system-jmx-connector-name="system" type="das-and-server">
+ <jmx-connector port="8686" address="0.0.0.0" security-enabled="false" name="system" auth-realm-name="admin-realm"></jmx-connector>
+ <das-config dynamic-reload-enabled="true" deploy-xml-validation="full" autodeploy-dir="${com.sun.aas.instanceRoot}/autodeploy" autodeploy-enabled="true"></das-config>
+ </admin-service>
+ <log-service log-rotation-limit-in-bytes="2000000" file="${com.sun.aas.instanceRoot}/logs/server.log">
+ <module-log-levels></module-log-levels>
+ </log-service>
+ <security-service>
+ <auth-realm classname="com.sun.enterprise.security.auth.realm.file.FileRealm" name="admin-realm">
+ <property name="file" value="${com.sun.aas.instanceRoot}/config/admin-keyfile"></property>
+ <property name="jaas-context" value="fileRealm"></property>
+ </auth-realm>
+ <auth-realm classname="com.sun.enterprise.security.auth.realm.file.FileRealm" name="file">
+ <property name="file" value="${com.sun.aas.instanceRoot}/config/keyfile"></property>
+ <property name="jaas-context" value="fileRealm"></property>
+ </auth-realm>
+ <auth-realm classname="com.sun.enterprise.security.auth.realm.certificate.CertificateRealm" name="certificate"></auth-realm>
+ <jacc-provider policy-provider="com.sun.enterprise.security.provider.PolicyWrapper" name="default" policy-configuration-factory-provider="com.sun.enterprise.security.provider.PolicyConfigurationFactoryImpl">
+ <property name="repository" value="${com.sun.aas.instanceRoot}/generated/policy"></property>
+ </jacc-provider>
+ <audit-module classname="com.sun.enterprise.security.ee.Audit" name="default">
+ <property name="auditOn" value="false"></property>
+ </audit-module>
+ <message-security-config auth-layer="SOAP">
+ <provider-config provider-type="client" provider-id="XWS_ClientProvider" class-name="com.sun.xml.wss.provider.ClientSecurityAuthModule">
+ <request-policy auth-source="content"></request-policy>
+ <response-policy auth-source="content"></response-policy>
+ <property name="encryption.key.alias" value="s1as"></property>
+ <property name="signature.key.alias" value="s1as"></property>
+ <property name="dynamic.username.password" value="false"></property>
+ <property name="debug" value="false"></property>
+ </provider-config>
+ <provider-config provider-type="client" provider-id="ClientProvider" class-name="com.sun.xml.wss.provider.ClientSecurityAuthModule">
+ <request-policy auth-source="content"></request-policy>
+ <response-policy auth-source="content"></response-policy>
+ <property name="encryption.key.alias" value="s1as"></property>
+ <property name="signature.key.alias" value="s1as"></property>
+ <property name="dynamic.username.password" value="false"></property>
+ <property name="debug" value="false"></property>
+ <property name="security.config" value="${com.sun.aas.instanceRoot}/config/wss-server-config-1.0.xml"></property>
+ </provider-config>
+ <provider-config provider-type="server" provider-id="XWS_ServerProvider" class-name="com.sun.xml.wss.provider.ServerSecurityAuthModule">
+ <request-policy auth-source="content"></request-policy>
+ <response-policy auth-source="content"></response-policy>
+ <property name="encryption.key.alias" value="s1as"></property>
+ <property name="signature.key.alias" value="s1as"></property>
+ <property name="debug" value="false"></property>
+ </provider-config>
+ <provider-config provider-type="server" provider-id="ServerProvider" class-name="com.sun.xml.wss.provider.ServerSecurityAuthModule">
+ <request-policy auth-source="content"></request-policy>
+ <response-policy auth-source="content"></response-policy>
+ <property name="encryption.key.alias" value="s1as"></property>
+ <property name="signature.key.alias" value="s1as"></property>
+ <property name="debug" value="false"></property>
+ <property name="security.config" value="${com.sun.aas.instanceRoot}/config/wss-server-config-1.0.xml"></property>
+ </provider-config>
+ </message-security-config>
+ </security-service>
+ <monitoring-service>
+ <module-monitoring-levels></module-monitoring-levels>
+ </monitoring-service>
+ <diagnostic-service></diagnostic-service>
+ <java-config debug-options="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9009" system-classpath="${com.sun.aas.installRoot}/lib/appserv-launch.jar" classpath-suffix="">
+ <jvm-options>-client</jvm-options>
+ <jvm-options>-Djava.endorsed.dirs=${com.sun.aas.installRoot}/lib/endorsed</jvm-options>
+ <jvm-options>-Djava.security.policy=${com.sun.aas.instanceRoot}/config/server.policy</jvm-options>
+ <jvm-options>-Djava.security.auth.login.config=${com.sun.aas.instanceRoot}/config/login.conf</jvm-options>
+ <jvm-options>-Dsun.rmi.dgc.server.gcInterval=3600000</jvm-options>
+ <jvm-options>-Dsun.rmi.dgc.client.gcInterval=3600000</jvm-options>
+ <jvm-options>-Xmx512m</jvm-options>
+ <jvm-options>-Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/keystore.jks</jvm-options>
+ <jvm-options>-Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/cacerts.jks</jvm-options>
+ <jvm-options>-Djava.ext.dirs=${com.sun.aas.javaRoot}/lib/ext${path.separator}${com.sun.aas.javaRoot}/jre/lib/ext${path.separator}${com.sun.aas.instanceRoot}/lib/ext${path.separator}${com.sun.aas.derbyRoot}/lib</jvm-options>
+ <jvm-options>-Djdbc.drivers=org.apache.derby.jdbc.ClientDriver</jvm-options>
+ <jvm-options>-Dcom.sun.enterprise.config.config_environment_factory_class=com.sun.enterprise.config.serverbeans.AppserverConfigEnvironmentFactory</jvm-options>
+ <jvm-options>-Dcom.sun.enterprise.taglibs=javax.servlet.jsp.jstl.jar,javax.faces.jar</jvm-options>
+ <jvm-options>-Dcom.sun.enterprise.taglisteners=javax.faces.jar</jvm-options>
+ <jvm-options>-XX:NewRatio=2</jvm-options>
+ </java-config>
+ <thread-pools>
+ <thread-pool thread-pool-id="thread-pool-1"></thread-pool>
+ </thread-pools>
+ <network-config>
+ <protocols>
+ <protocol name="http-listener-1">
+ <http header-buffer-length="8192" forced-response-type="text/plain; charset=iso-8859-1" default-virtual-server="server" max-connections="250" server-name="" default-response-type="text/plain; charset=iso-8859-1">
+ <file-cache enabled="false"></file-cache>
+ </http>
+ </protocol>
+ <protocol security-enabled="true" name="http-listener-2">
+ <http header-buffer-length="8192" forced-response-type="text/plain; charset=iso-8859-1" default-virtual-server="server" max-connections="250" server-name="" default-response-type="text/plain; charset=iso-8859-1">
+ <file-cache enabled="false"></file-cache>
+ </http>
+ <ssl ssl2-enabled="true" cert-nickname="s1as" client-auth-enabled="true"></ssl>
+ </protocol>
+ <protocol name="admin-listener">
+ <http header-buffer-length="8192" forced-response-type="text/plain; charset=iso-8859-1" default-virtual-server="__asadmin" max-connections="250" server-name="" default-response-type="text/plain; charset=iso-8859-1">
+ <file-cache enabled="false"></file-cache>
+ </http>
+ </protocol>
+ </protocols>
+ <network-listeners>
+ <thread-pool max-thread-pool-size="20" min-thread-pool-size="2" thread-pool-id="http-thread-pool" max-queue-size="4096"></thread-pool>
+ <network-listener port="8080" protocol="http-listener-1" transport="tcp" name="http-listener-1" thread-pool="http-thread-pool"></network-listener>
+ <network-listener port="8181" protocol="http-listener-2" transport="tcp" name="http-listener-2" thread-pool="http-thread-pool"></network-listener>
+ <network-listener port="4848" enabled="false" protocol="admin-listener" transport="tcp" name="admin-listener" thread-pool="http-thread-pool"></network-listener>
+ </network-listeners>
+ <transports>
+ <transport name="tcp"></transport>
+ </transports>
+ </network-config>
+ </config>
+ </configs>
+ <servers>
+ <server name="server" config-ref="server-config">
+ <application-ref ref="adminapp" virtual-servers="__asadmin"></application-ref>
+ <application-ref ref="admingui" virtual-servers="__asadmin"></application-ref>
+ <application-ref ref="JBIFramework"></application-ref>
+ <application-ref ref="WSTXServices"></application-ref>
+ <application-ref ref="WSTCPConnectorLCModule"></application-ref>
+ <resource-ref ref="jdbc/__TimerPool"></resource-ref>
+ <resource-ref ref="jdbc/__CallFlowPool"></resource-ref>
+ <resource-ref ref="jdbc/__default"></resource-ref>
+ </server>
+ </servers>
+ <property name="administrative.domain.name" value="domain1"></property>
+</domain>