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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352; (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 &#2325;&#2375;&#2342;&#2366;&#2352; (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 &#2325;&#2375;&#2342;&#2366;&#2352; (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>&nbsp;<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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352 (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 &#2325;&#2375;&#2342;&#2366;&#2352 (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>&lt;action-report description="xxx" exit-code="xxx" [failure-cause="xxx"]>
+ * <br>&nbsp;&nbsp;&lt;message-part message="xxx">
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="xxx" value="xxx"/>
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;...
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;message-part message="xxx" type="xxx">
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;...
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/message-part>
+ * <br>&nbsp;&nbsp;&lt/message-part>
+ * <br>&nbsp;&nbsp;&lt;action-report ...> [for subactions]
+ * <br>&nbsp;&nbsp;...
+ * <br>&nbsp;&nbsp;&lt;/action-report>
+ * <br>&lt;/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>&lt;action-report description="xxx" exit-code="xxx" [failure-cause="xxx"]>
+ * <br>&nbsp;&nbsp;&lt;message-part message="">
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="xxx" value="xxx"/>
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;...
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;<i>child-type</i> <i>property</i>="value"/>
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;...
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/<i>child-type</i>>
+ * <br>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/message-part>
+ * <br>&nbsp;&nbsp;&lt/message-part>
+ * <br>&lt;/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&lt;String&gt; 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>