org.glassfish.appclient.client.acc.AppClientInfo Maven / Gradle / Ivy
/*
* 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.deployment.Application;
import com.sun.enterprise.deployment.ApplicationClientDescriptor;
import com.sun.enterprise.deployment.PersistenceUnitDescriptor;
import com.sun.enterprise.deployment.archivist.Archivist;
import com.sun.enterprise.deployment.util.AnnotationDetector;
import com.sun.enterprise.util.LocalStringManager;
import com.sun.enterprise.util.LocalStringManagerImpl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.glassfish.apf.AnnotationProcessorException;
import org.glassfish.api.deployment.InstrumentableClassLoader;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.appclient.common.Util;
import org.glassfish.hk2.api.ServiceLocator;
import org.jvnet.hk2.annotations.Service;
import org.xml.sax.SAXParseException;
import jakarta.persistence.EntityManagerFactory;
/**
*Represents information about the app client, regardless of what type of
*archive (jar or directory) it is stored in or what type of module
*(app client or nested within an ear) that archive holds.
*
*@author tjquinn
*/
@Service
public abstract class AppClientInfo {
public static final String USER_CODE_IS_SIGNED_PROPERTYNAME = "com.sun.aas.user.code.signed";
private static final String SIGNED_USER_CODE_PERMISSION_TEMPLATE_NAME = "jwsclientSigned.policy";
private static final String UNSIGNED_USER_CODE_PERMISSION_TEMPLATE_NAME = "jwsclientUnsigned.policy";
private static final String CODE_BASE_PLACEHOLDER_NAME = "com.sun.aas.jws.client.codeBase";
/** logger */
protected Logger _logger;
// /** abstract representation of the storage location */
// private ReadableArchive appClientArchive = null;
// /** original appclient (file or directory) */
// private File appClientArchive = null;
// private ReadableArchive appClient;
/** abstract archivist able to operate on the module in the location
* (specified by archive */
private Archivist archivist = null;
/** main class name as the user specified it on the command line */
protected String mainClassFromCommandLine;
/**
*main class to be used - could come from the command line or from the
*manifest of the selected app client archive
*/
protected String mainClassNameToRun = null;
/** class loader - cached */
private ClassLoader classLoader = null;
/** indicates if the app client has been launched using Java Web Start */
protected boolean isJWS = false;
/**
* descriptor from the app client module or a default one for the
* .class file case and the regular java launch with main class case
*/
private ApplicationClientDescriptor acDesc = null;
/** access to the localizable strings */
private static final LocalStringManager localStrings =
new LocalStringManagerImpl(AppClientInfo.class);
// XXX Mitesh helping to update this
// private PersistenceUnitLoader.ApplicationInfo puAppInfo;
// /**
// *Creates a new instance of AppClientInfo. Always invoked from subclasse
// *because AppClientInfo is abstract.
// *
// *Note that any code instantiationg one of the concrete subclasses MUST
// *invoke completeInit after this super.constructor has returned.
// *
// *@param isJWS indicates if ACC has been launched using Java Web Start
// *@param logger the logger to use for messages
// *@param archive the AbstractArchive for the app client module or
// * directory being launched
// *@param archivist the Archivist corresponding to the type of module
// * in the archive
// *@param mainClassFromCommandLine the main class name specified on the
// * command line (null if not specified)
// */
// public AppClientInfo(boolean isJWS, Logger logger, ReadableArchive appClientarchive,
// Archivist archivist, String mainClassFromCommandLine) {
// this.isJWS = isJWS;
// _logger = logger;
// this.appClientArchive = appClientarchive;
// this.archivist = archivist;
// this.mainClassFromCommandLine = mainClassFromCommandLine;
// }
/**
* Creates a new AppClientInfo for a main class file.
*
* @param isJWS
* @param logger
* @param mainClassFromCommandLine
*/
public AppClientInfo(boolean isJWS, Logger logger, String mainClassFromCommandLine) {
this.isJWS = isJWS;
_logger = logger;
this.mainClassFromCommandLine = mainClassFromCommandLine;
}
protected void setDescriptor(ApplicationClientDescriptor acDesc) {
this.acDesc = acDesc;
}
protected ApplicationClientDescriptor getDescriptor() {
return acDesc;
}
protected void completeInit() throws Exception {
}
// /**
// *Finishes initialization work.
// *
// *The calling logic that instantiates this object must invoke completeInit
// *after instantiation but before using the object.
// *@throws IOException for errors opening the expanded archive
// *@throws SAXParseException for errors parsing the descriptors in a newly-opened archive
// *@throws ClassNotFoundException if the main class requested cannot be located in the archive
// *@throws URISyntaxException if preparing URIs for the class loader fails
// *
// */
// protected void completeInit(URL[] persistenceURLs)
// throws IOException, SAXParseException, ClassNotFoundException,
// URISyntaxException, AnnotationProcessorException, Exception {
//
// //expand if needed. initialize the appClientArchive
//// appClientArchive = expand(appClientArchive);
//
// //Create the class loader to be used for persistence unit checking,
// //validation, and running the app client.
// classLoader = createClassLoader(appClientArchive, persistenceURLs);
//
// //Populate the deployment descriptor without validation.
// //Note that validation is done only after the persistence handling
// //has instructed the classloader created above.
// populateDescriptor(appClientArchive, archivist, classLoader);
//
// //If the selected app client depends on at least one persistence unit
// //then handle the P.U. before proceeding.
// if (appClientDependsOnPersistenceUnit(getAppClient())) {
// //@@@check to see if the descriptor is metadata-complet=true
// //if not, we would have loaded classes into the classloader
// //during annotation processing. we need to hault and ask
// //the user to deploy the application.
// //if (!getAppClient().isFullFlag()) {
// // throw new RuntimeException("Please deploy your application");
// //}
// handlePersistenceUnitDependency();
// }
//
// //Now that the persistence handling has run and instrumented the class
// //loader - if it had to - it's ok to validate.
// archivist.validate(classLoader);
//
// fixupWSDLEntries();
//
// if (isJWS) {
// grantRequestedPermissionsToUserCode();
// }
// }
/**
*Returns the app client descriptor to be run.
*@return the descriptor for the selected app client
*/
protected ApplicationClientDescriptor getAppClient() {
return getAppClient(archivist);
}
protected ClassLoader getClassLoader() {
return classLoader;
}
protected void close() throws IOException {
}
protected boolean deleteAppClientDir() {
return !_keepExplodedDir;
}
protected String getLocalString(final String key, final String defaultMessage,
final Object... args) {
String result = localStrings.getLocalString(this.getClass(),
key, defaultMessage, args);
return result;
}
/**
*Processes persistence unit handling for the ACC.
*/
protected void handlePersistenceUnitDependency()
throws URISyntaxException, MalformedURLException {
// XXX Mitesh helping to update this
// this.puAppInfo = new ApplicationInfoImpl(this);
// new PersistenceUnitLoaderImpl().load(puAppInfo);
}
/**
* implementation of
* {@link com.sun.enterprise.server.PersistenceUnitLoader.ApplicationInfo}.
*/
private static class ApplicationInfoImpl
// XXX Mitesh helping to update this
// implements PersistenceUnitLoader.ApplicationInfo
{
private AppClientInfo outer; // the outer object we are associated with
private ApplicationClientDescriptor appClient;
public ApplicationInfoImpl(AppClientInfo outer) {
this.outer = outer;
appClient = outer.getAppClient();
}
//TODO: This method does not appear to be used -- can it be deleted?
public Application getApplication(ServiceLocator habitat) {
Application application = appClient.getApplication();
if (application == null) {
application = Application.createVirtualApplication(
appClient.getModuleID(),
appClient.getModuleDescriptor());
}
return application;
}
public InstrumentableClassLoader getClassLoader() {
return (InstrumentableClassLoader) outer.getClassLoader();
}
// public String getApplicationLocation() {
// return outer.appClientArchive.getURI().toASCIIString();
// }
/**
* @return list of PU that are actually referenced by the
* appclient.
*/
public Collection extends PersistenceUnitDescriptor>
getReferencedPUs() {
return appClient.findReferencedPUs();
}
/**
* @return list of EMFs that have been loaded for this appclient.
*/
public Collection extends EntityManagerFactory> getEntityManagerFactories() {
Collection emfs =
new HashSet();
if (appClient.getApplication() != null) {
emfs.addAll(appClient.getApplication()
.getEntityManagerFactories());
}
emfs.addAll(appClient.getEntityManagerFactories());
return emfs;
}
} // end of class ApplicationInfoImpl
/**
*Reports whether the app client's descriptor shows a dependence on a
*persistence unit.
*@param descr the descriptor for the app client in question
*@returns true if the descriptor shows such a dependency
*/
protected boolean descriptorContainsPURefcs(
ApplicationClientDescriptor descr) {
return ! descr.getEntityManagerFactoryReferenceDescriptors().isEmpty();
}
/**
*Reports whether the main class in the archive contains annotations that
*refer to persistence units.
*@return boolean if the main class contains annotations that refer to a pers. unit
*/
protected static URL getEntryAsUrl(File moduleLocation, String uri)
throws MalformedURLException, IOException {
URL url = null;
try {
url = new URL(uri);
} catch(java.net.MalformedURLException e) {
// ignore
url = null;
}
if (url!=null) {
return url;
}
if( moduleLocation != null ) {
if( moduleLocation.isFile() ) {
url = createJarUrl(moduleLocation, uri);
} else {
String path = uri.replace('/', File.separatorChar);
url = new File(moduleLocation, path).toURI().toURL();
}
}
return url;
}
private static URL createJarUrl(File jarFile, String entry)
throws MalformedURLException, IOException {
return new URL("jar:" + jarFile.toURI().toURL() + "!/" + entry);
}
// XXX restore or move elsewhere -- grants permissions to jars expanded from v2 generated JAR
// /**
// *Granting the appropriate level of permissions to user code, emulating
// *the Java Web Start behavior as required in the JNLP spec.
// *
// *Classes from the user's app client jar are loaded using the ASURLClassLoader
// *rather than the Java Web Start class loader. As a result, Java Web Start
// *cannot grant the appropriate level of permissions to the user code since
// *it is the JWS class loader that does that. So we need to grant the user
// *code the appropriate level of permissions, based on whether the user's
// *app client jar was signed or not.
// *@param retainTempFiles indicates whether to keep the generated policy file
// */
// protected void grantRequestedPermissionsToUserCode() throws IOException, URISyntaxException {
// /*
// *Create a temporary file containing permissions grants. We will use
// *this temp file to refresh the Policy objects's settings. The temp
// *file will contain one segment for each element in the class path
// *for the user code (from the expanded generated app client jar).
// *The permissions granted will be the same for all class path elements,
// *and the specific settings will either be the sandbox permissions
// *as described in the JNLP spec or full permissions.
// */
// boolean userJarIsSigned = Boolean.getBoolean(USER_CODE_IS_SIGNED_PROPERTYNAME);
//
// boolean retainTempFiles = Boolean.getBoolean(AppClientContainer.APPCLIENT_RETAIN_TEMP_FILES_PROPERTYNAME);
//
// /*
// *Use a template to construct each part of the policy file, choosing the
// *template based on whether the user code is signed or not.
// */
// String templateName = (userJarIsSigned ? SIGNED_USER_CODE_PERMISSION_TEMPLATE_NAME : UNSIGNED_USER_CODE_PERMISSION_TEMPLATE_NAME);
// String template = Util.loadResource(JWSACCMain.class, templateName);
//
// /*
// *Create the temporary policy file to write to.
// */
// File policyFile = File.createTempFile("accjws-user", ".policy");
// if ( ! retainTempFiles) {
// policyFile.deleteOnExit();
// }
//
// PrintStream ps = null;
//
// try {
// ps = new PrintStream(policyFile);
//
// Properties p = new Properties();
//
// /*
// *Use the list of class paths already set up on the ASURLClassLoader.
// *Then for each element in the class path, write a part of the policy
// *file granting the privs specified in the selected template to the code path.
// */
// ASURLClassLoader loader = (ASURLClassLoader) getClassLoader();
// for (URL classPathElement : loader.getURLs()) {
// /*
// *Convert the URL into a proper codebase expression suitable for
// *a grant clause in the policy file.
// */
// String codeBase = Util.URLtoCodeBase(classPathElement);
// if (codeBase != null) {
// p.setProperty(CODE_BASE_PLACEHOLDER_NAME, codeBase);
// String policyPart = Util.replaceTokens(template, p);
//
// ps.println(policyPart);
// }
// }
//
// /*
// *Close the temp file and use it to refresh the current Policy object.
// */
// ps.close();
//
// JWSACCMain.refreshPolicy(policyFile);
//
// if ( ! retainTempFiles) {
// policyFile.delete();
// }
// } finally {
// if (ps != null) {
// ps.close();
// }
// }
// }
/////////////////////////////////////////////////////////////////
// The following protected methods are overridden by at least //
// one of the sub classes. //
/////////////////////////////////////////////////////////////////
// /**
// *Expands the contents of the source archive into a temporary
// *directory, using the same format as backend server expansions.
// *@param file an archive file to be expanded
// *@return an opened archive for the expanded directory archive
// *@exception IOException in case of errors during the expansion
// */
// protected abstract ReadableArchive expand(File file)
// throws IOException, Exception;
protected ApplicationClientDescriptor getAppClient(
Archivist archivist) {
return ApplicationClientDescriptor.class.cast(
archivist.getDescriptor());
}
protected String getAppClientRoot(
ReadableArchive archive, ApplicationClientDescriptor descriptor) {
return archive.getURI().toASCIIString();
}
protected void massageDescriptor()
throws IOException, AnnotationProcessorException {
//default behavor: no op
}
protected List getClassPaths(ReadableArchive archive) {
List paths = new ArrayList();
paths.add(archive.getURI().toASCIIString());
return paths;
}
/**
*Returns the main class that should be executed.
*@return the name of the main class to execute when the client starts
*/
protected String getMainClassNameToRun(ApplicationClientDescriptor acDescr) {
if (mainClassNameToRun == null) {
if (mainClassFromCommandLine != null) {
mainClassNameToRun = mainClassFromCommandLine;
_logger.fine("Main class is " + mainClassNameToRun + " from command line");
} else {
/*
*Find out which class to execute from the descriptor.
*/
mainClassNameToRun = getAppClient().getMainClassName();
_logger.fine("Main class is " + mainClassNameToRun + " from descriptor");
}
}
return mainClassNameToRun;
}
protected boolean classContainsAnnotation(
String entry, AnnotationDetector detector,
ReadableArchive archive, ApplicationClientDescriptor descriptor)
throws FileNotFoundException, IOException {
return detector.containsAnnotation(archive, entry);
// String acRoot = getAppClientRoot(archive, descriptor);
// String entryLocation = acRoot + File.separator + entry;
// File entryFile = new File(entryLocation);
// return detector.containsAnnotation(archive, entry)
// return detector.containsAnnotation(entryFile);
}
@Override
public String toString() {
String lineSep = System.getProperty("line.separator");
StringBuilder result = new StringBuilder();
result.append(this.getClass().getName() + ": " + lineSep);
result.append(" isJWS: " + isJWS);
// result.append(" archive file: " + appClientArchive.getURI().toASCIIString() + lineSep);
// result.append(" archive type: " + appClientArchive.getClass().getName() + lineSep);
result.append(" archivist type: " + archivist.getClass().getName() + lineSep);
result.append(" main class to be run: " + mainClassNameToRun + lineSep);
// result.append(" temporary archive directory: " + appClientArchive.getURI() + lineSep);
result.append(" class loader type: " + classLoader.getClass().getName() + lineSep);
return result.toString();
}
//for debug purpose
protected static final boolean _keepExplodedDir =
Boolean.getBoolean("appclient.keep.exploded.dir");
}