All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.appclient.server.core.AppClientDeployer Maven / Gradle / Ivy

There is a newer version: 6.2024.6
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2014 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
// Portions Copyright [2019-2021] Payara Foundation and/or affiliates

package org.glassfish.appclient.server.core;

import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.Applications;
import com.sun.enterprise.module.HK2Module;
import java.io.IOException;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.ApplicationClientDescriptor;
import com.sun.enterprise.deployment.archivist.AppClientArchivist;
import com.sun.enterprise.module.HK2Module;
import com.sun.enterprise.module.ModulesRegistry;
import com.sun.logging.LogDomains;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.logging.Logger;
import jakarta.inject.Inject;
import jakarta.inject.Named;

import org.glassfish.api.deployment.DeploymentContext;
import org.glassfish.api.deployment.MetaData;
import org.glassfish.api.deployment.UndeployCommandParameters;
import org.glassfish.appclient.server.core.jws.servedcontent.ASJarSigner;
import org.glassfish.deployment.common.DeploymentException;
import org.glassfish.javaee.core.deployment.JavaEEDeployer;

import org.jvnet.hk2.annotations.Service;
import org.glassfish.hk2.api.PostConstruct;
import jakarta.inject.Singleton;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.appclient.server.core.jws.JWSAdapterManager;
import org.glassfish.appclient.server.core.jws.JavaWebStartInfo;
import org.glassfish.deployment.common.Artifacts;
import org.glassfish.deployment.common.DeploymentUtils;
/**
 * AppClient module deployer.
 * 

* Prepares JARs for download to the admin client and tracks which JARs should * be downloaded for each application. (Downloads occur during * deploy --retrieve or get-client-stubs command * processing, or during Java Web Start launches of app clients. Also creates * AppClientServerApplication instances for each client to provide Java Web Start * support. *

* Main responsibilities: *

    *
  • create a new facade JAR for each of the developer's original app client * JARs, and *
  • create a new facade JAR for the EAR (if the app client is part of an EAR), and *
  • manage internal data structures that map each deployed app to the app * client-related JARs that should be downloaded for that app. *
* Each app client facade JAR contains: *
    *
  • a manifest which: *
      *
    • lists the GlassFish app client facade class as the Main-Class *
    • contains a Class-Path entry referring to the developer's original JAR * and any JARs in the EAR's library directory, *
    • contains a GlassFish-specific item that is a relative URI pointing to the * corresponding original JAR *
    • contains a GlassFish-specific item identifying the main class in the * developer's original JAR *
    • contains a copy of the SplashScreen-Image item from the developer's * original JAR, if there is one *
    *
  • the app client facade main class that prepares the ACC runtime environment before * transferring control to the developer's main class *
  • a copy of the splash screen image from the developer's original JAR, if * there is one *
* * If the app client being deployed is part of an EAR, then the EAR facade * represents an "app client group" and contains: *
    *
  • a manifest which: *
      *
    • declares the GlassFish EAR facade class as the Main-Class *
    • lists the URIs to the individual app client facade JARs in a * GlassFish-specific item *
    *
  • the GlassFish app client group facade main class *
*

* For backward compatibility, the generated facade JAR is named * ${appName}Client.jar and is downloaded into the local directory the user * specifies on the deploy --retrieve or get-client-stubs * command. Other JARs - the developer's original app client JAR(s) * and any required library JARs - are downloaded into a subdirectory within * that local directory named ${appName}Client. This segregates the files for * different clients into different subdirectories to avoid naming collisions if * the user downloads multiple clients into the same local directory. * * @author tjquinn * */ @Service @Singleton public class AppClientDeployer extends JavaEEDeployer implements PostConstruct { private Logger logger; public static final String APPCLIENT_FACADE_CLASS_FILE = "org/glassfish/appclient/client/AppClientFacade.class"; public static final String APPCLIENT_AGENT_MAIN_CLASS_FILE = "org/glassfish/appclient/client/JWSAppClientContainerMain.class"; public static final String APPCLIENT_COMMAND_CLASS_NAME = "org.glassfish.appclient.client.AppClientFacade"; public static final Attributes.Name GLASSFISH_APPCLIENT_MAIN_CLASS = new Attributes.Name("GlassFish-AppClient-Main-Class"); public static final Attributes.Name SPLASH_SCREEN_IMAGE = new Attributes.Name("SplashScreen-Image"); public static final Attributes.Name GLASSFISH_APP_NAME = new Attributes.Name("GlassFish-App-Name"); private static final String GF_CLIENT_MODULE_NAME = "fish.payara.server.appclient.gf-client-module"; /** Save the helper across phases in the deployment context's appProps */ public static final String HELPER_KEY_NAME = "org.glassfish.appclient.server.core.helper"; @Inject protected Domain domain; @Inject private ModulesRegistry modulesRegistry; @Inject private Applications applications; @Inject private ASJarSigner jarSigner; @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) Config config; // private DownloadableArtifacts downloadInfo = null; /** * Maps the app name to the user-friendly context root for that app. */ private final Map appAndClientNameToUserFriendlyContextRoot = new HashMap(); /** the class loader which knows about the org.glassfish.main.appclient.gf-client-module */ private ClassLoader gfClientModuleClassLoader; /* * Each app client server application will listen for config change * events - for creation, deletion, or change of java-web-start-enabled * property settings. Because they are not handled as services hk2 will * not automatically register them for notification. This deployer, though, * is a service and so by implementing ConfigListener is registered * by hk2 automatically for config changes. The following Set collects * all app client server applications so the deployer can forward * notifications to each app client server app. */ final private Set appClientApps = new HashSet(); public AppClientDeployer() { } @Override public void postConstruct() { logger = Logger.getLogger(JavaWebStartInfo.APPCLIENT_SERVER_MAIN_LOGGER, JavaWebStartInfo.APPCLIENT_SERVER_LOGMESSAGE_RESOURCE); for (HK2Module module : modulesRegistry.getModules(GF_CLIENT_MODULE_NAME)) { gfClientModuleClassLoader = module.getClassLoader(); } } @Override public MetaData getMetaData() { return new MetaData(false, null, new Class[]{Application.class}); } @Override public AppClientServerApplication load(AppClientContainerStarter containerStarter, DeploymentContext dc) { // if the populated DOL object does not container appclient // descriptor, this is an indication that appclient deployer // should not handle this module ApplicationClientDescriptor appclientDesc = dc.getModuleMetaData(ApplicationClientDescriptor.class); if (appclientDesc == null) { return null; } appclientDesc.setClassLoader(dc.getClassLoader()); AppClientDeployerHelper helper = null; try { helper = getSavedHelperOrCreateHelper(dc); } catch (IOException ex) { throw new RuntimeException(ex); } // helper.addGroupFacadeToEARDownloads(); final AppClientServerApplication newACServerApp = newACServerApp(dc, helper); appClientApps.add(newACServerApp); return newACServerApp; } public Set appClientApps() { return appClientApps; } private AppClientServerApplication newACServerApp( final DeploymentContext dc, final AppClientDeployerHelper helper) { final AppClientServerApplication result = habitat.getService(AppClientServerApplication.class); result.init(dc, helper); return result; } @Override public void unload(AppClientServerApplication application, DeploymentContext dc) { appClientApps.remove(application); } /** * Clean any files and artifacts that were created during the execution * of the prepare method. * * @param dc deployment context */ @Override public void clean(DeploymentContext dc) { super.clean(dc); UndeployCommandParameters params = dc.getCommandParameters(UndeployCommandParameters.class); if (params != null) { final com.sun.enterprise.config.serverbeans.Application app = applications.getApplication(params.name); DeploymentUtils.downloadableArtifacts(app).clearArtifacts(); } } @Override protected void generateArtifacts(DeploymentContext dc) throws DeploymentException { // if the populated DOL object does not container appclient // descriptor, this is an indication that appclient deployer // should not handle this module if (dc.getModuleMetaData(ApplicationClientDescriptor.class) == null) { return; } try { final AppClientDeployerHelper helper = createAndSaveHelper( dc, gfClientModuleClassLoader); helper.prepareJARs(); addArtifactsToDownloads(helper, dc); addArtifactsToGeneratedFiles(helper, dc); recordUserFriendlyContextRoot(helper, dc); } catch (Exception ex) { throw new DeploymentException(ex); } } /** * Records the user-friendly path as a property for the app client module. * This is primarily for ease-of-lookup from GetRelativeJWSURICommand. * * @param helper * @param dc */ private void recordUserFriendlyContextRoot(final AppClientDeployerHelper helper, final DeploymentContext dc) { final String path = JWSAdapterManager.userFriendlyContextRoot(helper.appClientDesc(), dc.getAppProps()); dc.getModuleProps().put("jws.user.friendly.path", path); } private void addArtifactsToDownloads( final AppClientDeployerHelper helper, final DeploymentContext dc) throws IOException { final Artifacts downloadInfo = DeploymentUtils.downloadableArtifacts(dc); downloadInfo.addArtifacts(helper.earLevelDownloads()); downloadInfo.addArtifacts(helper.clientLevelDownloads()); } private void addArtifactsToGeneratedFiles( final AppClientDeployerHelper helper, final DeploymentContext dc) throws IOException { final Artifacts generatedFileInfo = DeploymentUtils.generatedArtifacts(dc); generatedFileInfo.addArtifacts(helper.earLevelDownloads()); generatedFileInfo.addArtifacts(helper.clientLevelDownloads()); } private AppClientDeployerHelper createAndSaveHelper(final DeploymentContext dc, final ClassLoader clientModuleLoader) throws IOException { final AppClientArchivist archivist = habitat.getService(AppClientArchivist.class); final AppClientDeployerHelper h = AppClientDeployerHelper.newInstance( dc, archivist, clientModuleLoader, habitat, jarSigner); dc.addTransientAppMetaData(HELPER_KEY_NAME + moduleURI(dc), h.proxy()); return h; } private AppClientDeployerHelper getSavedHelperOrCreateHelper(final DeploymentContext dc) throws IOException { final String key = HELPER_KEY_NAME + moduleURI(dc); AppClientDeployerHelper h = null; final AppClientDeployerHelper.Proxy p = dc.getTransientAppMetaData(key, AppClientDeployerHelper.Proxy.class); if (p != null) { h = p.helper(); } if (h == null) { h = dc.getTransientAppMetaData(key, StandaloneAppClientDeployerHelper.class); } if (h == null) { /* * We are probably loading a previously-deployed app client, so * the helper has not be created yet. Create it. */ h = createAndSaveHelper(dc, gfClientModuleClassLoader); } return h; } private String moduleURI(final DeploymentContext dc) { ApplicationClientDescriptor acd = dc.getModuleMetaData(ApplicationClientDescriptor.class); return acd.getModuleDescriptor().getArchiveUri(); } public void recordContextRoot(final String appName, final String clientURIWithinEAR, final String userFriendlyContextRoot) { appAndClientNameToUserFriendlyContextRoot.put( keyToAppAndClientNameMap(appName, clientURIWithinEAR), userFriendlyContextRoot); } public void removeContextRoot(final String appName, final String clientURIWithinEAR) { appAndClientNameToUserFriendlyContextRoot.remove( keyToAppAndClientNameMap(appName, clientURIWithinEAR)); } /** * Returns the user-friendly context root for the specified app client. *

* Primarily used from the admin console for retrieving the context path * for launching the specified app client. * @param appName * @param clientModuleURI * @return */ public String userFriendlyContextRoot(final String appName, final String clientModuleURI) { return appAndClientNameToUserFriendlyContextRoot.get( keyToAppAndClientNameMap(appName, clientModuleURI)); } private String keyToAppAndClientNameMap(final String appName, final String moduleURIText) { return appName + "/" + (moduleURIText == null ? appName : moduleURIText); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy