Skip to content

Commit

Permalink
Merge pull request #9775 from tbitonti/anno-cache-jaxws23
Browse files Browse the repository at this point in the history
Wire anno caching into JAXWS 23; augment tracing.
  • Loading branch information
tbitonti authored Nov 19, 2019
2 parents 3cd7e2b + 5c10f59 commit a7e1d16
Show file tree
Hide file tree
Showing 4 changed files with 364 additions and 137 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package com.ibm.ws.jaxws23.web;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
Expand All @@ -27,6 +28,7 @@
import com.ibm.websphere.ras.Tr;
import com.ibm.websphere.ras.TraceComponent;
import com.ibm.ws.container.service.annotations.WebAnnotations;
import com.ibm.ws.container.service.annocache.AnnotationsBetaHelper;
import com.ibm.ws.container.service.app.deploy.extended.ExtendedModuleInfo;
import com.ibm.ws.jaxws.JaxWsConstants;
import com.ibm.ws.jaxws.metadata.EndpointType;
Expand All @@ -45,6 +47,7 @@
import com.ibm.wsspi.adaptable.module.Container;
import com.ibm.wsspi.adaptable.module.UnableToAdaptException;
import com.ibm.wsspi.anno.info.InfoStore;
import com.ibm.wsspi.anno.info.ClassInfo;
import com.ibm.wsspi.anno.targets.AnnotationTargets_Targets;
import com.ibm.wsspi.http.VirtualHost;
import com.ibm.wsspi.webcontainer.servlet.IServletConfig;
Expand All @@ -70,87 +73,224 @@ public WebJaxWsModuleInfoBuilder() {

@Override
public ExtendedModuleInfo build(ModuleMetaData moduleMetaData, Container containerToAdapt, JaxWsModuleInfo jaxWsModuleInfo) throws UnableToAdaptException {

// check if it is router web module for EJB based Web services
if (JaxWsUtils.isEJBModule(JaxWsMetaDataManager.getJaxWsModuleMetaData(moduleMetaData).getModuleContainer())) {
if ( JaxWsUtils.isEJBModule( JaxWsMetaDataManager.getJaxWsModuleMetaData(moduleMetaData).getModuleContainer() ) ) {
if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
Tr.debug(tc, "EJB module; ignore web services");
}
return null;
}

EndpointInfoBuilder endpointInfoBuilder = endpointInfoBuilderSRRef.getService();
if (endpointInfoBuilder == null) {
if ( endpointInfoBuilder == null ) {
if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
Tr.debug(tc, "Cannot get the EndpointInfoBuilder, will ignore all the Webservices.");
Tr.debug(tc, "No EndpointInfoBuilder; ignore web services");
}
return null;
}

WebAnnotations webAnnotations = containerToAdapt.adapt(WebAnnotations.class);
// TODO: The placement of the info store in the context is problematic:
// The value should be removed from the context and managed wholly
// within this builder.
//
// There are two problems: First, the reference persists into the
// postBuild call, where the info store is no longer open. Second,
// obtaining the store is expensive and should be avoided whenever
// possible.

WebAnnotations webAnnotations = AnnotationsBetaHelper.getWebAnnotations(containerToAdapt);
InfoStore infoStore = webAnnotations.getInfoStore();

EndpointInfoBuilderContext endpointInfoBuilderContext = new EndpointInfoBuilderContext(infoStore, containerToAdapt);
JaxWsModuleInfoBuilderContext jaxWsModuleInfoBuilderContext = new JaxWsModuleInfoBuilderContext(moduleMetaData, containerToAdapt, endpointInfoBuilderContext);
EndpointInfoBuilderContext endpointInfoBuilderContext =
new EndpointInfoBuilderContext(infoStore, containerToAdapt);

// Get all servlet name and class pairs in web.xml
Map<String, String> servletNameClassPairsInWebXML = getServletNameClassPairsInWebXML(containerToAdapt);
jaxWsModuleInfoBuilderContext.addContextEnv(JaxWsConstants.SERVLET_NAME_CLASS_PAIRS_FOR_EJBSINWAR, servletNameClassPairsInWebXML);
JaxWsModuleInfoBuilderContext jaxWsModuleInfoBuilderContext =
new JaxWsModuleInfoBuilderContext(moduleMetaData, containerToAdapt, endpointInfoBuilderContext);

// call the extensions to extra pre build the jaxWsModuleInfo, eg: endponitInfo for EJBs in War
for (JaxWsModuleInfoBuilderExtension extension : extensions) {
Map<String, String> servletNameClassPairsInWebXML =
getServletNameClassPairsInWebXML(containerToAdapt);

jaxWsModuleInfoBuilderContext.addContextEnv(
JaxWsConstants.SERVLET_NAME_CLASS_PAIRS_FOR_EJBSINWAR,
servletNameClassPairsInWebXML);

// call the extensions to extra pre build the jaxWsModuleInfo,
// eg: endpointInfo for EJBs in War
for ( JaxWsModuleInfoBuilderExtension extension : extensions ) {
extension.preBuild(jaxWsModuleInfoBuilderContext, jaxWsModuleInfo);
}

boolean didOpen = false;

try {
webAnnotations.openInfoStore();
WebAppConfig webAppConfig = containerToAdapt.adapt(WebAppConfig.class);

Set<String> presentedServices = jaxWsModuleInfo.getEndpointImplBeanClassNames();
WebAppConfig webAppConfig = containerToAdapt.adapt(WebAppConfig.class);
if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
Tr.debug(tc, "Presented service classes: " + presentedServices);
}

setupContextRoot(moduleMetaData, webAppConfig);
setupVirtualHostConfig(moduleMetaData, webAppConfig);
if (webAppConfig.isMetadataComplete()) {
// only scan the classes configured in web.xml
processClassesInWebXML(endpointInfoBuilder, endpointInfoBuilderContext, webAppConfig, jaxWsModuleInfo, presentedServices);
} else {
// scan all the classes in the application's classPath
Collection<String> implClassNamesInWebXML = servletNameClassPairsInWebXML.values();

AnnotationTargets_Targets annotationTargets = webAnnotations.getAnnotationTargets();
Set<String> serviceClassNames = new HashSet<String>();
if ( !webAppConfig.isMetadataComplete() ) {
Collection<String> implClassNamesInWebXML = servletNameClassPairsInWebXML.values();
if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
Tr.debug(tc, "Descriptor servlet class names: " + implClassNamesInWebXML);
}

// d95160: The prior implementation obtained classes from the SEED location.
// That implementation is not changed by d95160.

serviceClassNames.addAll(annotationTargets.getAnnotatedClasses(WebService.class.getName(),
AnnotationTargets_Targets.POLICY_SEED));
serviceClassNames.addAll(annotationTargets.getAnnotatedClasses(WebServiceProvider.class.getName(),
AnnotationTargets_Targets.POLICY_SEED));
AnnotationTargets_Targets annotationTargets = webAnnotations.getAnnotationTargets();

Set<String> serviceImplClassNames = annotationTargets.getAnnotatedClasses(WebService.class.getName());
if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
Tr.debug(tc, "WebService classes: " + serviceImplClassNames);
}
Set<String> providerImplClassNames = annotationTargets.getAnnotatedClasses(WebServiceProvider.class.getName());
if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
Tr.debug(tc, "WebServiceProvider classes: " + providerImplClassNames);
}
Set<String> implClassNames = new HashSet<String>( serviceImplClassNames.size() + providerImplClassNames.size() );
implClassNames.addAll(serviceImplClassNames);
implClassNames.addAll(providerImplClassNames);

for ( String implClassName : implClassNames ) {
String skipReason;
if ( implClassNamesInWebXML.contains(implClassName ) ) {
skipReason = "Listed in web.xml";
} else if ( presentedServices.contains(implClassName) ) {
skipReason = "Presentation service";
} else {
if ( !didOpen ) {
webAnnotations.openInfoStore();
didOpen = true;
}
// Don't need to call 'validAnnotations': Guaranteed to have
// WebService or WebServiceProvider.
skipReason = validModifiers( infoStore.getDelayableClassInfo(implClassName) );
}

for (String serviceImplBeanClassName : serviceClassNames) {
// if the serviceImplBeanClassName is in web.xml, just ignore here.
if (implClassNamesInWebXML.contains(serviceImplBeanClassName)
|| presentedServices.contains(serviceImplBeanClassName)
|| !JaxWsUtils.isWebService(infoStore.getDelayableClassInfo(serviceImplBeanClassName))) {
if ( skipReason != null ) {
if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
Tr.debug(tc, "Skip [ " + implClassName + " ]: " + skipReason);
}
continue;
} else {
if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
Tr.debug(tc, "Process [ " + implClassName + " ]");
}
}

jaxWsModuleInfo.addEndpointInfo(serviceImplBeanClassName,
endpointInfoBuilder.build(endpointInfoBuilderContext, serviceImplBeanClassName, EndpointType.SERVLET));
jaxWsModuleInfo.addEndpointInfo(
implClassName,
endpointInfoBuilder.build(endpointInfoBuilderContext, implClassName, EndpointType.SERVLET));
}
// now process the serviceImplBeanClassName in web.xml.
// maybe the serviceImplBeanClassName is in sharedLibs which can not be read by webAnnotations.getAnnotationTargets().
processClassesInWebXML(endpointInfoBuilder, endpointInfoBuilderContext, webAppConfig, jaxWsModuleInfo, presentedServices);
}

// now process the implClassName in web.xml.
// maybe the implClassName is in sharedLibs which
// can not be read by webAnnotations.getAnnotationTargets().

Iterator<IServletConfig> cfgIter = webAppConfig.getServletInfos();
while ( cfgIter.hasNext() ) {
IServletConfig servletCfg = cfgIter.next();

String servletName = servletCfg.getServletName();
String servletClassName = servletCfg.getClassName();

String skipReason;
if ( servletClassName == null ) {
skipReason = "Null servlet class name";
} else if ( presentedServices.contains(servletClassName) ) {
skipReason = "Presented Service";
} else {
if ( !didOpen ) {
webAnnotations.openInfoStore();
didOpen = true;
}
ClassInfo classInfo = infoStore.getDelayableClassInfo(servletClassName);
if ( (skipReason = validAnnotations(classInfo)) == null ) {
skipReason = validModifiers(classInfo);
}
}
if ( skipReason != null ) {
if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
Tr.debug(tc, "Skip servlet [ " + servletName + " : " + servletClassName + " ]: " + skipReason);
}
continue;
} else {
if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
Tr.debug(tc, "Process servlet [ " + servletName + " : " + servletClassName + " ]");
}
}

// Note that this step is only for servlet classes...
endpointInfoBuilderContext.addContextEnv(JaxWsConstants.ENV_ATTRIBUTE_ENDPOINT_SERVLET_NAME, servletName);

// ... but this step is performed for both non-servlet and servlet classes.
jaxWsModuleInfo.addEndpointInfo(
servletName,
endpointInfoBuilder.build(endpointInfoBuilderContext, servletClassName, EndpointType.SERVLET) );
}

} finally {
webAnnotations.closeInfoStore();
if ( didOpen ) {
webAnnotations.closeInfoStore();
}
}

// call the extensions to extra post build the jaxWsModuleInfo, eg: security settings
for (JaxWsModuleInfoBuilderExtension extension : extensions) {
for ( JaxWsModuleInfoBuilderExtension extension : extensions ) {
extension.postBuild(jaxWsModuleInfoBuilderContext, jaxWsModuleInfo);
}

return null;
}

// TODO: These tests use the info store, which does not account for
// metadata complete settings, and does not account for where
// the class lives in the class path.

private String validAnnotations(ClassInfo classInfo) {
if ( classInfo == null ) {
return "Class not found";
} else if ( !classInfo.isAnnotationPresent(WebService.class.getName()) &&
!classInfo.isAnnotationPresent(WebServiceProvider.class.getName()) ) {
return "No WebService or WebServiceProvider annotation";
} else {
return null;
}
}

// TODO: These might be recoded to use the targets table, but then
// they would be subject to target class selection limits.

private String validModifiers(ClassInfo classInfo) {
if ( classInfo == null ) {
return "Class not found";
} else {
String skipReason;
int modifiers = classInfo.getModifiers();
if ( !Modifier.isPublic(modifiers) ) {
skipReason = "Non-public modifier";
} else if ( Modifier.isFinal(modifiers) ) {
skipReason = "Modifier is final";
} else if ( Modifier.isAbstract(modifiers) ) {
skipReason = "Modifier is abstract";
} else {
skipReason = null;
}
if ( skipReason != null ) {
if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
skipReason += " [ 0x" + Integer.toHexString(modifiers) + " ]";
}
}
return skipReason;
}
}

private void setupContextRoot(ModuleMetaData moduleMetaData, WebAppConfig webAppConfig) {
JaxWsModuleMetaData jaxWsModuleMetaData = JaxWsMetaDataManager.getJaxWsModuleMetaData(moduleMetaData);
String contextRoot = webAppConfig.getContextRoot();
Expand Down Expand Up @@ -197,10 +337,6 @@ public Void run() {

/**
* Get all the Servlet name and className pairs from web.xml
*
* @param webAppConfig
* @return
* @throws UnableToAdaptException
*/
private Map<String, String> getServletNameClassPairsInWebXML(Container containerToAdapt) throws UnableToAdaptException {
Map<String, String> nameClassPairs = new HashMap<String, String>();
Expand All @@ -214,37 +350,7 @@ private Map<String, String> getServletNameClassPairsInWebXML(Container container
}
nameClassPairs.put(servletCfg.getServletName(), servletCfg.getClassName());
}

return nameClassPairs;
}

/**
* Process the serviceImplBean classes in web.xml file.
*
* @param ctx
* @param webAppConfig
* @param jaxWsModuleInfo
* @throws Exception
*/
private void processClassesInWebXML(EndpointInfoBuilder endpointInfoBuilder, EndpointInfoBuilderContext ctx, WebAppConfig webAppConfig,
JaxWsModuleInfo jaxWsModuleInfo, Set<String> presentedServices) throws UnableToAdaptException {

Iterator<IServletConfig> cfgIter = webAppConfig.getServletInfos();

while (cfgIter.hasNext()) {
IServletConfig servletCfg = cfgIter.next();

String servletClassName = servletCfg.getClassName();
if (servletClassName == null
|| presentedServices.contains(servletClassName)
|| !JaxWsUtils.isWebService(ctx.getInfoStore().getDelayableClassInfo(servletClassName))) {
continue;
}

String servletName = servletCfg.getServletName();
// add the servletName into EndpointInfoContext env
ctx.addContextEnv(JaxWsConstants.ENV_ATTRIBUTE_ENDPOINT_SERVLET_NAME, servletName);

jaxWsModuleInfo.addEndpointInfo(servletName, endpointInfoBuilder.build(ctx, servletClassName, EndpointType.SERVLET));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.ibm.websphere.ras.Tr;
import com.ibm.websphere.ras.TraceComponent;
import com.ibm.ws.container.service.annotations.WebAnnotations;
import com.ibm.ws.container.service.annocache.AnnotationsBetaHelper;
import com.ibm.ws.jaxws.JaxWsConstants;
import com.ibm.ws.jaxws.endpoint.EndpointPublisher;
import com.ibm.ws.jaxws.endpoint.EndpointPublisherManager;
Expand All @@ -39,6 +40,7 @@
import com.ibm.wsspi.webcontainer.extension.ExtensionProcessor;
import com.ibm.wsspi.webcontainer.metadata.WebModuleMetaData;
import com.ibm.wsspi.webcontainer.servlet.IServletContext;
import com.ibm.wsspi.anno.info.InfoStore;

public class JaxWsExtensionFactory implements ExtensionFactory {

Expand Down Expand Up @@ -108,8 +110,12 @@ public ExtensionProcessor createExtensionProcessor(IServletContext servletContex
WebApp webApp = (WebApp) servletContext;
publisherContext.setAttribute(JaxWsWebContainerConstants.NAMESPACE_COLLABORATOR, webApp.getCollaboratorHelper().getWebAppNameSpaceCollaborator());

publisherContext.setAttribute(JaxWsConstants.ENDPOINT_INFO_BUILDER_CONTEXT,
new EndpointInfoBuilderContext(servletContext.getModuleContainer().adapt(WebAnnotations.class).getInfoStore(), servletContext.getModuleContainer()));
WebAnnotations webAnnotations = AnnotationsBetaHelper.getWebAnnotations(servletContext.getModuleContainer());
InfoStore infoStore = webAnnotations.getInfoStore();

publisherContext.setAttribute(
JaxWsConstants.ENDPOINT_INFO_BUILDER_CONTEXT,
new EndpointInfoBuilderContext(infoStore,servletContext.getModuleContainer()));

// get endpoint publisher and do publish
EndpointPublisher endpointPublisher = endpointPublisherManagerRef.getServiceWithException().getEndpointPublisher(JaxWsConstants.WEB_ENDPOINT_PUBLISHER_TYPE);
Expand Down
Loading

0 comments on commit a7e1d16

Please sign in to comment.