alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (AppClientDeployerHelper.java)

This example Glassfish source code file (AppClientDeployerHelper.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

appclientdeployerhelper, appclientdeployerhelper, applicationclientdescriptor, deploymentcontext, file, io, ioexception, ioexception, jar, log, manifest, net, network, outputjararchive, outputstream, string, string, uri, uri, util

The Glassfish AppClientDeployerHelper.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 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.
 */

package org.glassfish.appclient.server.core;

import com.sun.enterprise.deploy.shared.FileArchive;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.ApplicationClientDescriptor;
import com.sun.enterprise.deployment.archivist.AppClientArchivist;
import com.sun.enterprise.deployment.deploy.shared.OutputJarArchive;
import com.sun.logging.LogDomains;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.api.admin.ProcessEnvironment;
import org.glassfish.api.deployment.DeployCommandParameters;
import org.glassfish.api.deployment.DeploymentContext;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.api.deployment.archive.WritableArchive;
import org.glassfish.appclient.server.core.jws.servedcontent.ASJarSigner;
import org.glassfish.appclient.server.core.jws.servedcontent.DynamicContent;
import org.glassfish.appclient.server.core.jws.servedcontent.FixedContent;
import org.glassfish.appclient.server.core.jws.servedcontent.StaticContent;
import org.glassfish.appclient.server.core.jws.servedcontent.TokenHelper;
import org.glassfish.deployment.common.Artifacts;
import org.glassfish.deployment.versioning.VersioningSyntaxException;
import org.glassfish.deployment.versioning.VersioningUtils;
import org.jvnet.hk2.component.Habitat;

/**
 * Encapsulates the details of generating the required JAR file(s),
 * depending on whether the app client is stand-alone or is nested
 * inside an EAR.
 * <p>
 * See also {@link StandaloneAppClientDeployerHelper} and
 * {@link NestedAppClientDeployerHelper}, the concrete implementation subclasses
 * of AppClientDeployerHelper.
 *
 * @author tjquinn
 */
public abstract class AppClientDeployerHelper {

    private final static String PERSISTENCE_XML_PATH = "META-INF/persistence.xml";
    
    private final DeploymentContext dc;
    private final ApplicationClientDescriptor appClientDesc;
    protected final AppClientArchivist archivist;
    private final String appName;
    private final String clientName;

    private final ClassLoader gfClientModuleClassLoader;

    private final Application application;

    private final Habitat habitat;

    private Logger logger = logger = LogDomains.getLogger(AppClientDeployerHelper.class, LogDomains.ACC_LOGGER);

    /**
     * Returns the correct concrete implementation of Helper.
     * @param dc the DeploymentContext for this deployment
     * @return an instance of the correct type of Helper
     * @throws java.io.IOException
     */
    static AppClientDeployerHelper newInstance(
            final DeploymentContext dc,
            final AppClientArchivist archivist,
            final ClassLoader gfClientModuleLoader,
            final Habitat habitat,
            final ASJarSigner jarSigner) throws IOException {
        ApplicationClientDescriptor bundleDesc = dc.getModuleMetaData(ApplicationClientDescriptor.class);
        Application application = bundleDesc.getApplication();
        boolean insideEar = ! application.isVirtual();

        return (insideEar ? new NestedAppClientDeployerHelper(
                                    dc,
                                    bundleDesc,
                                    archivist,
                                    gfClientModuleLoader,
                                    application,
                                    habitat,
                                    jarSigner)
                          : new StandaloneAppClientDeployerHelper(
                                    dc,
                                    bundleDesc,
                                    archivist,
                                    gfClientModuleLoader,
                                    application,
                                    habitat));
    }

    protected AppClientDeployerHelper(
            final DeploymentContext dc,
            final ApplicationClientDescriptor bundleDesc,
            final AppClientArchivist archivist,
            final ClassLoader gfClientModuleClassLoader,
            final Application application,
            final Habitat habitat) throws IOException {
        super();
        this.dc = dc;
        this.appClientDesc = bundleDesc;
        this.archivist = archivist;
        this.habitat = habitat;
        this.gfClientModuleClassLoader = gfClientModuleClassLoader;
        this.appName = appClientDesc.getApplication().getRegistrationName();
        this.clientName = appClientDesc.getModuleDescriptor().getArchiveUri();
        this.application = application;
    }

    /**
     * Returns the URI to the server's copy of the facade JAR file.
     * @param dc the deployment context for the current deployment
     * @return
     */
    public abstract URI facadeServerURI(DeploymentContext dc);

    /**
     * Returns the URI for the facade JAR, relative to the download
     * directory to which the user will fetch the relevant JARs (either
     * as part of "deploy --retrieve" or "get-client-stubs."
     * @param dc the deployment context for the current deployment
     * @return
     */
    public abstract URI facadeUserURI(DeploymentContext dc);

    /**
     * Returns the URI for the group facade JAR, relative to the download
     * directory to which the user will fetch the relevant JARs (either
     * as part of "deploy --retrieve" or "get-client-stubs."
     * @param dc the deployment context for the current deployment
     * @return
     */
    public abstract URI groupFacadeUserURI(DeploymentContext dc);

    public abstract URI groupFacadeServerURI(DeploymentContext dc);
    
    /**
     * Returns the file name (and type) for the facade, excluding any
     * directory information.
     * @param dc the deployment context for the current deployment
     * @return
     */
    protected abstract String facadeFileNameAndType(DeploymentContext dc);

    /**
     * Returns the URI to the developer's original app client JAR within
     * the download directory the user specifies in "deploy --retrieve" or
     * "get-client-stubs."
     * 
     * @param dc
     * @return
     */
    public abstract URI appClientUserURI(DeploymentContext dc);

    /**
     * Returns the URI to be used for the GlassFish-AppClient manifest entry
     * in the facade.
     * 
     * @param dc
     * @return
     */
    public abstract URI appClientUserURIForFacade(DeploymentContext dc);

    /**
     * Returns the URI to the server's copy of the developer's original app
     * client JAR.
     *
     * @param dc
     * @return
     */
    public abstract URI appClientServerURI(DeploymentContext dc);

    /**
     * Returns the URI on the server to the original location of the app client.
     * <p>
     * This is distinct from the appClientServerURI which could be in the
     * generated directory (in the case of a directory deployment, for example).
     * In some cases we need the original location of the app client on the
     * server (for example, to resolve relative references from the app client
     * JAR's manifest Class-Path).
     *
     * @param dc
     * @return
     */
    public abstract URI appClientServerOriginalAnchor(DeploymentContext dc);

    /**
     * Returns the URI within the enclosing app of the app client JAR.
     * Stand-alone app clients are considered to lie within an "implied"
     * containing app; the URI for such app clients is just the file name
     * and type.  The URI for nested app clients within an EAR is the
     * module URI to the app client.
     * 
     * @param dc
     * @return
     */
    public abstract URI appClientURIWithinApp(DeploymentContext dc);

    /**
     * Returns the relative path to the app client within the enclosing app.
     * The result will be an empty string for a stand-alone app clients because
     * it has no such path, in reality.  The result will be the relative URI
     * within the EAR for a nested app client.
     * @param dc
     * @return
     */
    public abstract String pathToAppclientWithinApp(DeploymentContext dc);

    /**
     * Returns a relative URI within the app directory for the specified
     * absolute URI.
     * @param dc
     * @param absoluteURI
     * @return
     */
    public abstract URI URIWithinAppDir(DeploymentContext dc,
            URI absoluteURI);
    /**
     *
     * Returns the class path to be stored in the manifest for the
     * generated facade JAR file.
     *
     * @return
     */
    protected abstract String facadeClassPath();

    protected abstract String PUScanTargets();

    public ApplicationSignedJARManager signedJARManager() {
        return null;
    }

    public abstract void createAndAddLibraryJNLPs(final AppClientDeployerHelper helper,
            final TokenHelper tHelper, final Map<String,DynamicContent> dynamicContent)
            throws IOException;
    
    public Map<String,Map signingAliasToJar() {
        return Collections.EMPTY_MAP;
    }

    public final DeploymentContext dc() {
        return dc;
    }

    public ApplicationClientDescriptor appClientDesc() {
        return appClientDesc;
    }

    public String appName() {
        return appName;
    }

    public String appName(final DeploymentContext dc) {
        DeployCommandParameters params = dc.getCommandParameters(DeployCommandParameters.class);
        return params.name();
    }

    public String clientName() {
        return clientName;
    }

    /**
     * Returns a FixedContent object for the file, within the EAR, at the
     * specified relative location.
     * 
     * @param uriString relative path within the EAR
     * @return FixedContent object for the file
     */
    public abstract FixedContent fixedContentWithinEAR(String uriString);

    /**
     * Returns the root directory for signed files in the applications.
     * @return File object for the signed JAR root directory
     */
    public abstract File rootForSignedFilesInApp();

    /**
     * If the specified URI is for an expanded submodule, makes a copy of
     * the submodule as a JAR and returns the URI for the copy.
     * @param classPathElement
     * @return URI to the safe copy of the submodule, relative to the top level
     * if the classPathElement is for a submodule; null otherwise
     */
    File JAROfExpandedSubmodule(final URI candidateSubmoduleURI) throws IOException {
        ReadableArchive source = new FileArchive();
        source.open(dc().getSource().getParentArchive().getURI().resolve(expandedDirURI(candidateSubmoduleURI)));
        OutputJarArchive target = new OutputJarArchive();
        target.create(dc().getScratchDir("xml").toURI().resolve(candidateSubmoduleURI));
        /*
         * Copy the manifest explicitly because the ReadableArchive
         * entries() method omits it.
         */
        Manifest mf = source.getManifest();
        OutputStream os = target.putNextEntry(JarFile.MANIFEST_NAME);
        mf.write(os);
        target.closeEntry();
        ClientJarMakerUtils.copyArchive(source, target, Collections.EMPTY_SET);
        target.close();
        return new File(target.getURI());
    }

    private URI expandedDirURI(final URI submoduleURI) {
        /*
         * The submodule URI (xxx.jar) might actually already be an expanded
         * directory.
         */
        final URI possibleExpandedDirURI = dc().getSource().getParentArchive().getURI().resolve(submoduleURI);
        final File possibleExpandedDir = new File(possibleExpandedDirURI);
        if (possibleExpandedDir.exists() && possibleExpandedDir.isDirectory()) {
            return submoduleURI;
        }
        final String uriText = submoduleURI.toString().replace("/", "__");
        int lastDot = uriText.lastIndexOf('.');
        return URI.create(uriText.substring(0, lastDot) + "_" + uriText.substring(lastDot + 1));
    }

    /**
     * Creates a generated manifest for either the facade (for app client or
     * EAR deployments both) and the ${appName}Client.jar
     * file if this is an app client deployment.
     * <p>
     * Most of the manifest's contents is derived from the source, with
     * the class path passed in as an argument because it varies between the facade and
     * the ${appName}Client.jar file.
     *
     * @param sourceManifest
     * @param facadeManifest
     * @param classpath space-separated list of class path elements
     */
    private void initGeneratedManifest(
            final Manifest sourceManifest,
            final Manifest generatedManifest,
            final String classPath,
            final String PUScanTargets,
            final Application application) {
        Attributes sourceMainAttrs = sourceManifest.getMainAttributes();
        Attributes facadeMainAttrs = generatedManifest.getMainAttributes();
        facadeMainAttrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
        facadeMainAttrs.put(Attributes.Name.MAIN_CLASS,
                AppClientDeployer.APPCLIENT_COMMAND_CLASS_NAME);
        facadeMainAttrs.put(AppClientDeployer.GLASSFISH_APPCLIENT_MAIN_CLASS,
                sourceMainAttrs.getValue(Attributes.Name.MAIN_CLASS));
        facadeMainAttrs.put(AppClientArchivist.GLASSFISH_APPCLIENT,
                appClientUserURIForFacade(dc).toASCIIString());
        String splash = sourceMainAttrs.getValue(AppClientDeployer.SPLASH_SCREEN_IMAGE);
        if (splash != null) {
            facadeMainAttrs.put(AppClientDeployer.SPLASH_SCREEN_IMAGE, splash);
        }
        facadeMainAttrs.put(Attributes.Name.CLASS_PATH, classPath);
        if (PUScanTargets != null) {
            facadeMainAttrs.put(AppClientArchivist.GLASSFISH_CLIENT_PU_SCAN_TARGETS_NAME,
                    PUScanTargets);
        }
        facadeMainAttrs.put(AppClientDeployer.GLASSFISH_APP_NAME, application.getAppName());

        facadeMainAttrs.put(AppClientArchivist.GLASSFISH_ANCHOR_DIR, anchorDirRelativeToClient());
        
        if ( ! appClientDesc.isStandalone()) {
//            final DownloadableArtifacts.FullAndPartURIs earFacadeDownload =
//                dc().getTransientAppMetaData("earFacadeDownload", DownloadableArtifacts.FullAndPartURIs.class);

            facadeMainAttrs.put(AppClientArchivist.GLASSFISH_GROUP_FACADE,
                    relativePathToGroupFacade());
        }
    }

    private String anchorDirRelativeToClient() {
        final String pathToClient = pathToAppclientWithinApp(dc);
        final StringBuilder sb = new StringBuilder();
        for (char c : pathToClient.toCharArray()) {
            if (c == '/') {
                sb.append("../");
            }
        }
        return sb.toString();
    }

    protected URI relativeURIToGroupFacade() {
        return URI.create(relativePathToGroupFacade());
    }
    
    private String relativePathToGroupFacade() {
        final StringBuilder sb = new StringBuilder(anchorDirRelativeToClient());
        try {
            /*
             * One more level up because the group facade will reside in the
             * download directory.
             */
            sb.append("../").append(VersioningUtils.getUntaggedName(appName)).append("Client.jar");
        } catch (VersioningSyntaxException ex) {
            logger.log(Level.SEVERE, ex.getMessage(), ex);
        }
        return sb.toString();
    }

    private void writeUpdatedDescriptors(final OutputJarArchive facadeArchive, final ApplicationClientDescriptor acd) throws IOException {
        archivist.setDescriptor(acd);
        archivist.writeDeploymentDescriptors(facadeArchive);
    }

    protected void prepareJARs() throws IOException, URISyntaxException {
        // In embedded mode, we don't process app clients so far.
        if (habitat.getComponent(ProcessEnvironment.class).getProcessType().isEmbedded()) {
            return;
        }
        generateAppClientFacade();
    }


    protected final void generateAppClientFacade() throws IOException, URISyntaxException {
        OutputJarArchive facadeArchive = new OutputJarArchive();
        /*
         * Make sure the directory subtree to contain the facade exists.  If the
         * client URI within the EAR contains a directory then that directory
         * probably does not exist in the generated dir for this app...not yet
         * anyway...it is about to exist.
         */
        final File facadeFile = new File(facadeServerURI(dc));
        if ( ! facadeFile.getParentFile().exists()) {
            facadeFile.getParentFile().mkdirs();
        }
        facadeArchive.create(facadeServerURI(dc));
        ReadableArchive source = dc.getSource();
        Manifest sourceManifest = source.getManifest();
        if (sourceManifest == null) {
            final String msg = logger.getResourceBundle().getString("enterprise.deployment.appclient.noManifest");
            throw new IOException(MessageFormat.format(msg, source.getURI().toASCIIString()));
        }
        Manifest facadeManifest = facadeArchive.getManifest();
        initGeneratedManifest(sourceManifest, facadeManifest, 
                facadeClassPath(), PUScanTargets(), application);
        /*
         * If the developer's app client JAR contains a splash screen, copy
         * it from the original JAR to the facade so the Java launcher can
         * display it when the app client is launched.
         */
        final Attributes srcMainAttrs = sourceManifest.getMainAttributes();
        if (srcMainAttrs == null) {
            final String msg = logger.getResourceBundle().getString("enterprise.deployment.appclient.noMainAttrs");
            throw new IOException(MessageFormat.format(msg, source.getURI().toASCIIString()));
        }
        String splash = srcMainAttrs.getValue(AppClientDeployer.SPLASH_SCREEN_IMAGE);
        if (splash != null) {
            ClientJarMakerUtils.copy(source, facadeArchive, splash);
        }
        /*
         * Write the manifest to the facade.
         */
        OutputStream os = facadeArchive.putNextEntry(JarFile.MANIFEST_NAME);
        facadeManifest.write(os);
        facadeArchive.closeEntry();
        /*
         * Write the updated descriptors to the facade.
         */
        writeUpdatedDescriptors(facadeArchive, appClientDesc);

        /*
         * Because of how persistence units are discovered and added to the
         * app client DOL object when the archivist reads the descriptor file,
         * add any META-INF/persistence.xml file from the developer's client
         * to the client facade.  (The generated descriptor and the
         * persistence.xml files need to be in the same archive.)
         */
        copyPersistenceUnitXML(source, facadeArchive);

        copyMainClass(facadeArchive);

        facadeArchive.close();
    }

    private void copyClass(final WritableArchive facadeArchive,
            final String classResourcePath) throws IOException {
        OutputStream os = facadeArchive.putNextEntry(classResourcePath);
        InputStream is = openByteCodeStream("/" + classResourcePath);

        copyStream(is, os);
        try {
            is.close();
            facadeArchive.closeEntry();
        } catch (IOException ignore) {
        }
    }
    

    private void copyAgentMainClass(final WritableArchive facadeArchive) throws IOException {
        copyClass(facadeArchive, AppClientDeployer.APPCLIENT_AGENT_MAIN_CLASS_FILE);
    }

    private void copyMainClass(final WritableArchive facadeArchive) throws IOException {
        copyClass(facadeArchive, AppClientDeployer.APPCLIENT_FACADE_CLASS_FILE);
    }

    private void copyPersistenceUnitXML(final ReadableArchive sourceClient,
            final WritableArchive facadeArchive) throws IOException {
        InputStream persistenceXMLStream = sourceClient.getEntry(PERSISTENCE_XML_PATH);
        if (persistenceXMLStream != null) {
            OutputStream os = facadeArchive.putNextEntry(PERSISTENCE_XML_PATH);
            copyStream(persistenceXMLStream, os);
            try {
                persistenceXMLStream.close();
                facadeArchive.closeEntry();
            } catch (IOException ignore) {
            }
        }
    }

    protected InputStream openByteCodeStream(final String resourceName) throws IOException {
        URL url = gfClientModuleClassLoader.getResource(resourceName);
        if (url == null) {
            throw new IllegalArgumentException(resourceName);
        }
        InputStream is = url.openStream();
        return is;
    }

    protected abstract Set<Artifacts.FullAndPartURIs> clientLevelDownloads() throws IOException;

    public abstract Set<Artifacts.FullAndPartURIs> earLevelDownloads() throws IOException;

    protected abstract void addGroupFacadeToEARDownloads();
    
    static void copyStream(InputStream in, OutputStream out) throws IOException {
        byte[] buf = new byte[4096];
        int len;
        while ((len = in.read(buf)) >= 0) {
            out.write(buf, 0, len);
        }
    }

    Proxy proxy() {
        return new Proxy(this);
    }

    /**
     * Wrapper around AppClientDeployer for storage in the deployment context's
     * meta data.
     * <p>
     * Storage and retrieval of meta data is type-based.  We cannot retrieve
     * stored AppClientDeployerHelper by type alone because the actual instance
     * is one of the concrete subclasses.  So this wrapper provides a way to
     * store a single type in the meta data so we can retrieve it.
     */
    public static class Proxy {
        private final AppClientDeployerHelper helper;

        public Proxy(final AppClientDeployerHelper helper) {
            this.helper = helper;
        }

        public AppClientDeployerHelper helper() {
            return helper;
        }
    }
}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish AppClientDeployerHelper.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.