org.glassfish.appclient.client.acc.UndeployedLaunchable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 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.client.acc;
import com.sun.enterprise.deploy.shared.ArchiveFactory;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.ApplicationClientDescriptor;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.archivist.AppClientArchivist;
import com.sun.enterprise.deployment.archivist.Archivist;
import com.sun.enterprise.deployment.archivist.ArchivistFactory;
import com.sun.enterprise.deployment.util.DOLUtils;
import org.glassfish.api.deployment.archive.ArchiveType;
import org.glassfish.deployment.common.ModuleDescriptor;
import com.sun.enterprise.universal.i18n.LocalStringsImpl;
import java.io.IOException;
import java.net.URI;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.deployment.common.RootDeploymentDescriptor;
import org.glassfish.hk2.api.ServiceLocator;
import org.xml.sax.SAXParseException;
import javax.enterprise.deploy.shared.ModuleType;
/**
*
* @author tjquinn
*/
public class UndeployedLaunchable implements Launchable {
private static final LocalStringsImpl localStrings = new LocalStringsImpl(UndeployedLaunchable.class);
private final String callerSuppliedMainClassName;
private ApplicationClientDescriptor acDesc = null;
private AppClientArchivist archivist = null;
private final ReadableArchive clientRA;
private ClassLoader classLoader = null;
static UndeployedLaunchable newUndeployedLaunchable(
final ServiceLocator habitat,
final ReadableArchive ra,
final String callerSuppliedMainClassName,
final String callerSuppliedAppName,
final ClassLoader classLoader) throws IOException, SAXParseException, UserError {
ArchivistFactory af = Util.getArchivistFactory();
/*
* Try letting the factory decide what type of archive this is. That
* will often allow an app client or an EAR archive to be detected
* automatically.
*/
Archivist archivist = af.getArchivist(ModuleType.CAR.toString(), classLoader);
if (archivist == null) {
throw new UserError(localStrings.get("appclient.invalidArchive",
ra.getURI().toASCIIString()));
}
final ArchiveType moduleType = archivist.getModuleType();
if (moduleType != null && moduleType.equals(DOLUtils.carType())) {
return new UndeployedLaunchable(habitat, ra,
(AppClientArchivist) archivist, callerSuppliedMainClassName);
} else if (moduleType != null && moduleType.equals(DOLUtils.earType())) {
/*
* Locate the app client submodule that matches the main class name
* or the app client name.
*/
Application app = (Application) archivist.open(ra);
for (ModuleDescriptor md : app.getModules()) {
if ( ! md.getModuleType().equals(DOLUtils.carType())) {
continue;
}
ApplicationClientDescriptor acd = (ApplicationClientDescriptor) md.getDescriptor();
final String displayName = acd.getDisplayName();
final String appName = acd.getModuleID();
ArchiveFactory archiveFactory = Util.getArchiveFactory();
ReadableArchive clientRA = archiveFactory.openArchive(ra.getURI().resolve(md.getArchiveUri()));
/*
* Choose this nested app client if the caller-supplied name
* matches, or if the caller-supplied main class matches, or
* if neither was provided.
*/
final boolean useThisClient =
(displayName != null && displayName.equals(callerSuppliedAppName))
|| (appName != null && appName.equals(callerSuppliedAppName))
|| (callerSuppliedMainClassName != null && clientRA.exists(classToResource(callerSuppliedMainClassName))
|| (callerSuppliedAppName == null && callerSuppliedMainClassName == null));
if (useThisClient) {
return new UndeployedLaunchable(habitat, clientRA, acd,
callerSuppliedMainClassName);
}
clientRA.close();
}
throw new UserError(localStrings.get("appclient.noMatchingClientInEAR",
ra.getURI(), callerSuppliedMainClassName, callerSuppliedAppName));
} else {
/*
* There is a possibility that the user is trying to launch an
* archive that is more than one type of archive: such as an EJB
* but also an app client (because the manifest identifies a main
* class, for example).
*
* Earlier the archivist factory might have returned the other type
* of archivist - such as the EJB archivist. Now see if the app
* client archivist will work when selected directly.
*/
archivist = af.getArchivist(DOLUtils.carType());
/*
* Try to open the archive as an app client archive just to see
* if it works.
*/
RootDeploymentDescriptor tempACD = archivist.open(ra);
if (tempACD != null && tempACD instanceof ApplicationClientDescriptor) {
/*
* Start with a fresh archivist - unopened - so we can request
* anno processing, etc. before opening it for real.
*/
archivist = af.getArchivist(DOLUtils.carType());
return new UndeployedLaunchable(habitat, ra, (AppClientArchivist) archivist,
callerSuppliedMainClassName);
}
throw new UserError(
localStrings.get("appclient.unexpectedArchive", ra.getURI()));
}
}
public URI getURI() {
return clientRA.getURI();
}
public String getAnchorDir() {
return null;
}
private static String classToResource(final String className) {
return className.replace('.', '/') + ".class";
}
private UndeployedLaunchable(final ServiceLocator habitat,
final ReadableArchive clientRA,
final String callerSuppliedMainClass) throws IOException, SAXParseException {
this.callerSuppliedMainClassName = callerSuppliedMainClass;
this.clientRA = clientRA;
}
private UndeployedLaunchable(final ServiceLocator habitat,
final ReadableArchive clientRA,
final ApplicationClientDescriptor acd,
final String callerSuppliedMainClass) throws IOException, SAXParseException {
this(habitat, clientRA, callerSuppliedMainClass);
this.acDesc = acd;
}
private UndeployedLaunchable(final ServiceLocator habitat,
final ReadableArchive clientRA,
final AppClientArchivist archivist,
final String callerSuppliedMainClass) throws IOException, SAXParseException {
this(habitat, clientRA, callerSuppliedMainClass);
this.archivist = completeInit(archivist);
}
public Class getMainClass() throws ClassNotFoundException {
try {
String mainClassName = mainClassNameToLaunch();
return Class.forName(mainClassName, true, getClassLoader());
} catch (Exception e) {
throw new ClassNotFoundException("");
}
}
private ClassLoader getClassLoader() {
if (classLoader == null) {
classLoader = Thread.currentThread().getContextClassLoader();
}
return classLoader;
}
private String mainClassNameToLaunch() throws IOException, SAXParseException {
return (callerSuppliedMainClassName != null ? callerSuppliedMainClassName :
extractMainClassFromArchive(clientRA));
}
private String extractMainClassFromArchive(final ReadableArchive clientRA) throws IOException {
final Manifest mf = clientRA.getManifest();
if (mf == null) {
return null;
}
return mf.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
}
public ApplicationClientDescriptor getDescriptor(final URLClassLoader loader) throws IOException, SAXParseException {
this.classLoader = loader;
if (acDesc == null) {
final AppClientArchivist _archivist = getArchivist(
AccessController.doPrivileged(new PrivilegedAction() {
@Override
public ACCClassLoader run() {
return new ACCClassLoader(loader.getURLs(), loader.getParent());
}
}));
_archivist.setAnnotationProcessingRequested(true);
acDesc = _archivist.open(clientRA);
Application.createVirtualApplication(null, acDesc.getModuleDescriptor());
acDesc.getApplication().setAppName(getDefaultApplicationName(clientRA));
}
return acDesc;
}
public String getDefaultApplicationName(ReadableArchive archive) {
String appName = archive.getName();
int lastDot = appName.lastIndexOf('.');
if (lastDot != -1) {
if (appName.substring(lastDot).equalsIgnoreCase(".ear") ||
appName.substring(lastDot).equalsIgnoreCase(".jar")) {
appName = appName.substring(0, lastDot);
}
}
return appName;
}
private AppClientArchivist completeInit(final AppClientArchivist arch) {
arch.setDescriptor(acDesc);
arch.setAnnotationProcessingRequested(true);
return arch;
}
private AppClientArchivist getArchivist(final ClassLoader classLoader) throws IOException {
if (archivist == null) {
ArchivistFactory af = Util.getArchivistFactory();
archivist = completeInit((AppClientArchivist) af.getArchivist(ModuleType.CAR.toString()));
}
archivist.setClassLoader(classLoader);
return archivist;
}
public void validateDescriptor() {
try {
getArchivist(classLoader).validate(classLoader);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}