How to create authorization header for Log4j2 HTTP appender? - http

Is there a proper way to create an authorization header that can regenerated every time you POST using the HTTP appender?
Background: The authorization header needs to be calculated every time we POST data to the api. This auth is the only method that is accepted via the API. It consists of a signature,ID,and the epoch time. It wont be able to be set as an environment variable because the api will not accept auth headers older than X minutes.
My current method is this: I am trying to use the Scripts in the configuration of the log4j2 to return a value that will be used in the HTTP appender
https://logging.apache.org/log4j/2.x/manual/configuration.html#Scripts
Here is my log4j2http.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" name="MyApp">
<Scripts>
<Script name="selector" language="groovy">
<![CDATA[
import org.apache.commons.codec.binary.Hex
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import java.security.MessageDigest
def id="XXXXXXXXXXXXXx"
Long epoch_time = System.currentTimeMillis()
Mac hmac = Mac.getInstance("HmacSHA256")
hmac.init(new SecretKeySpec(key.getBytes(), "HmacSHA256"))
def signature = Hex.encodeHexString(hmac.doFinal("GET${epoch_time}${path}".getBytes())).bytes.encodeBase64()
return "${id}:${signature}:${epoch_time}"
]]>
</Script>
</Scripts>
<Appenders>
<Http name="Http" url="https://XXX/rest/log/ingest" method="POST">
<KeyValuePair key="_Id:" value="{Id:"588"}" />
<Property name="Authorization" value="${result}" />
<Property name="Accept" value="application/json" />
<JsonLayout properties="true" />
</Http>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Http" />
</Root>
</Loggers>
</Configuration>
App:
package App;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import java.io.*;
public class App {
public static void main(String[] args) {
System.setProperty("log4j2.Script.enableLanguages","groovy");
System.setProperty("log4j2.debug","false");
Logger logger = LogManager.getLogger("App");
LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
File file = new File("log4j2http.xml");
context.setConfigLocation(file.toURI());
logger.debug("Debug log");
}
}
I'm not getting an error , just an empty ${result}. It is making me think that importing the groovy libraries is not working correctly or the script itself has errors. With debug on, it doesn't seem that I can see if the script is executing correctly. This likely doesn't seem to be the correct method nor do I know if this is possible.
2022-10-09 00:58:39,198 main DEBUG Installed 2 script engines
2022-10-09 00:58:39,251 main DEBUG Groovy Scripting Engine version: 2.0, language: Groovy, threading: MULTITHREADED, compile: true, names: [groovy, Groovy], factory class: org.codehaus.groovy.jsr223.GroovyScriptEngineFactory
2022-10-09 00:58:39,252 main DEBUG PluginManager 'Core' found 127 plugins
2022-10-09 00:58:39,252 main DEBUG PluginManager 'Level' found 0 plugins
2022-10-09 00:58:39,257 main DEBUG PluginManager 'Lookup' found 16 plugins
2022-10-09 00:58:39,259 main DEBUG Building Plugin[name=Script, class=org.apache.logging.log4j.core.script.Script].
2022-10-09 00:58:39,278 main DEBUG PluginManager 'TypeConverter' found 26 plugins
2022-10-09 00:58:39,292 main DEBUG createScript(name="selector", language="groovy", scriptText=".................")
2022-10-09 00:58:39,292 main DEBUG Building Plugin[name=scripts, class=org.apache.logging.log4j.core.config.ScriptsPlugin].
2022-10-09 00:58:39,295 main DEBUG createScripts(={selector})
2022-10-09 00:58:39,297 main DEBUG Script selector is compilable
2022-10-09 00:58:40,383 main DEBUG Building Plugin[name=KeyValuePair, class=org.apache.logging.log4j.core.util.KeyValuePair].
2022-10-09 00:58:40,388 main DEBUG KeyValuePair$Builder(key="_Id:", value="{Id:"588"}")
2022-10-09 00:58:40,389 main DEBUG Building Plugin[name=property, class=org.apache.logging.log4j.core.config.Property].
2022-10-09 00:58:40,389 main DEBUG createProperty(name="Authorization", value="${result}", value="null")

Related

NLog throws 'Target cannot be found' for any custom target running on Azure Web App

I've created two NLog custom targets on .NET Standard 2.0, and imported them into an existing ASP.NET 4.7.2 website.
nlog.config looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Info"
internalLogFile="${basedir}/internal-nlog.txt"
throwExceptions="true"
throwConfigExceptions="true">
<extensions>
<add assembly="MyAssembly"/>
</extensions>
<targets async="false">
<target name="logconsole" xsi:type="Console" />
<target xsi:type="AzureTableTarget"
name="azureTable"
// some configs
/>
<target xsi:type="PostmarkLogTarget"
name="postmark"
// some configs
/>
</targets>
<rules>
<logger name="*" minlevel="Warn" writeTo="postmark" />
<logger name="*" minlevel="Info" writeTo="azureTable" />
<logger name="*" minlevel="Debug" writeTo="logconsole" />
</rules>
</nlog>
When the app starts locally, everything works fine. When it starts on the Azure App Service, I get this in the nlog internal log (and a big, fat error page):
2019-06-21 15:08:53.5719 Info Message Template Auto Format enabled
2019-06-21 15:08:53.6015 Info Loading assembly: MyAssembly
2019-06-21 15:08:53.6926 Info Adding target ConsoleTarget(Name=logconsole)
2019-06-21 15:08:53.7595 Error Parsing configuration from D:\home\site\wwwroot\NLog.config failed. Exception: NLog.NLogConfigurationException: Exception when parsing D:\home\site\wwwroot\NLog.config. ---> System.ArgumentException: Target cannot be found: 'AzureTableTarget'
at NLog.Config.Factory`2.CreateInstance(String itemName)
at NLog.Config.LoggingConfigurationParser.ParseTargetsElement(ILoggingConfigurationElement targetsElement)
at NLog.Config.LoggingConfigurationParser.ParseNLogSection(ILoggingConfigurationElement configSection)
at NLog.Config.XmlLoggingConfiguration.ParseNLogSection(ILoggingConfigurationElement configSection)
at NLog.Config.LoggingConfigurationParser.LoadConfig(ILoggingConfigurationElement nlogConfig, String basePath)
at NLog.Config.XmlLoggingConfiguration.ParseNLogElement(ILoggingConfigurationElement nlogElement, String filePath, Boolean autoReloadDefault)
at NLog.Config.XmlLoggingConfiguration.ParseTopLevel(NLogXmlElement content, String filePath, Boolean autoReloadDefault)
at NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)
--- End of inner exception stack trace ---
2019-06-21 15:08:53.8489 Error Failed loading from config file location: D:\home\site\wwwroot\NLog.config Exception: NLog.NLogConfigurationException: Exception when parsing D:\home\site\wwwroot\NLog.config. ---> System.ArgumentException: Target cannot be found: 'AzureTableTarget'
at NLog.Config.Factory`2.CreateInstance(String itemName)
at NLog.Config.LoggingConfigurationParser.ParseTargetsElement(ILoggingConfigurationElement targetsElement)
at NLog.Config.LoggingConfigurationParser.ParseNLogSection(ILoggingConfigurationElement configSection)
at NLog.Config.XmlLoggingConfiguration.ParseNLogSection(ILoggingConfigurationElement configSection)
at NLog.Config.LoggingConfigurationParser.LoadConfig(ILoggingConfigurationElement nlogConfig, String basePath)
at NLog.Config.XmlLoggingConfiguration.ParseNLogElement(ILoggingConfigurationElement nlogElement, String filePath, Boolean autoReloadDefault)
at NLog.Config.XmlLoggingConfiguration.ParseTopLevel(NLogXmlElement content, String filePath, Boolean autoReloadDefault)
at NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)
--- End of inner exception stack trace ---
at NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)
at NLog.Config.XmlLoggingConfiguration..ctor(XmlReader reader, String fileName, Boolean ignoreErrors, LogFactory logFactory)
at NLog.Config.LoggingConfigurationFileLoader.LoadXmlLoggingConfiguration(XmlReader xmlReader, String configFile, LogFactory logFactory)
at NLog.Config.LoggingConfigurationFileLoader.LoadXmlLoggingConfigurationFile(LogFactory logFactory, String configFile)
at NLog.Config.LoggingConfigurationFileLoader.TryLoadLoggingConfiguration(LogFactory logFactory, String configFile, LoggingConfiguration& config)
2019-06-21 15:08:54.1153 Info Configuring from an XML element in D:\home\site\wwwroot\NLog.config...
2019-06-21 15:08:54.1457 Info Message Template Auto Format enabled
2019-06-21 15:08:54.1457 Info Loading assembly: MyAssembly
2019-06-21 15:08:54.1457 Info Adding target ConsoleTarget(Name=logconsole)
2019-06-21 15:08:54.3332 Info Adding target AzureTableTarget(Name=azureTable)
2019-06-21 15:08:54.3525 Info Adding target PostmarkLogTarget(Name=postmark)
2019-06-21 15:08:54.4120 Info Found 38 configuration items
2019-06-21 15:08:54.4738 Info Configuration initialized.
The second load comes about because I have code in global.asax.cs to register and configure the targets specifically. This code fires immediately after setting up AutoFac, and before anything tries to log to anywhere.
Running locally, the code proceeds through these steps in order, even in Release mode. It looks like it tries to log a message before configuration has completed when running on Azure.
Even if that were the case, both custom targets have default public constructors, so NLog should be able to instantiate them automagically. (Which is why I reload configs after setting up the targets.)
Two questions:
What is different about the Azure App Service that causes (or allows) NLog to jump the gun like that?
Short of removing nlog.config and setting up logging in code, how can I prevent this behavior from happening?
Target cannot be found: 'AzureTableTarget'
This mean that the target class 'AzureTableTarget' cannot be found in one of the assemblies and thus an instance cannot be create.
You need to tell NLog in which assembly the AzureTableTarget type could be found.
Something like this:
<extensions>
<add assembly="AssemblyNameWhereAzureTableTargetIsDefined"/>
</extensions>
What is different about the Azure App Service that causes (or allows) NLog to jump the gun like that?
Are the same assemblies available? So is the assembly with the AzureTableTarget published?
Short of removing nlog.config and setting up logging in code
For this case it doesn't matter if NLog is configured from file or from code.
how can I prevent this behavior from happening?
Always add all external NLog extensions to <extensions>
Last but not least, throwExceptions="true" isn't recommend for production! (If your logging breaks, do you really like that your application breaks?)
Found it. Wow.
I had this code hanging out in a .cs file:
public static readonly Logger Logger = LogManager.GetCurrentClassLogger();
On the App Service deployment, the static constructor of the class containing that line ran before App_Start had finished. On my local box, it didn't.
So I changed it to this:
public static Logger Logger => _logger ?? (_logger = LogManager.GetCurrentClassLogger());
private static Logger _logger;
...and everything works now. The Logger is only created when used, not just because ASP.NET wanted to instantiate static classes ahead of time.

Swagger not giving UI for Spring MVC Project

I am new to the Swagger and trying to implement it in the Spring MVC. I'm using latest dependency swagger-springmvc from http://mvnrepository.com/artifact/com.mangofactory/swagger-springmvc. So based on link https://dzone.com/articles/documenting-your-spring-api. I added following configuration in mvc-config.xml.
<!-- Serve static content - required for Swagger -->
<mvc:default-servlet-handler/>
<!-- to enable the default documentation controller-->
<context:component-scan base-package="com.mangofactory.swagger.controllers"/>
<!-- to pick up the bundled spring configuration-->
<context:component-scan base-package="com.mangofactory.swagger.configuration"/>
<!-- Direct static mappings -->
<mvc:resources mapping="*.html" location="/, classpath:/swagger-ui"/>
Also I used following from link shown above.
<bean class="com.xxx.xx.xx.SwaggerConfig"/>
Then I added
git clone https://github.com/wordnik/swagger-ui
cp -r swagger-ui/dist ~/dev/x-auth-security/src/main/webapps/docs
When I launch the site: http://localhost:8080/dp-rest/api-docs I don't see UI format, it only gives JSON format.
{"apiVersion":"1.0","swaggerVersion":"1.2","apis":[{"path":"/default/student-service","description":"Manage Student Service","position":0},{"path":"/default/student-service","description":"Manage Student Service","position":0}],"authorizations":[],"info":{"title":"Student API's","description":"API for Student ","termsOfServiceUrl":"terms.html","contact":"test#yahoo.com","license":"Commercial Proprietary","licenseUrl":"http://www.adbc.com"}}
Ny
#Configuration
#EnableSwagger
public class SwaggerConfig {
private SpringSwaggerConfig springSwaggerConfig;
#Autowired
public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig) {
this.springSwaggerConfig = springSwaggerConfig;
}
#Bean
// Don't forget the #Bean annotation
public SwaggerSpringMvcPlugin customImplementation() {
return new SwaggerSpringMvcPlugin(this.springSwaggerConfig).apiInfo(
apiInfo()).includePatterns(".*");
}
private ApiInfo apiInfo() {
return new ApiInfo("Student API", "API for Student",
"term.html", "test#tahoo.com",
"Commercial Proprietary", "http://www.test.com");
}
}
Why UI format not coming when we launch the http://localhost:8080/sample-rest/api-docs site?
Then only I see raw JSON response not any ui, What is missing here? What I need to changed/add/modify my code?
According to the article you'll see a section that tells you where to find the documentation. I'm not sure if you're using spring-boot but...
After making these changes, I was able to open fire up the app with "mvn spring-boot:run" and view http://localhost:8080/docs/index.html in my browser.
In any case, swagger-springmvc is now called springfox and supports the latest swagger specification (2.0). There is also documentation available to help you get started. I would recommend using the latest version (2.3.1 as of this writing) of springfox instead.

Spring MVC Mixing xml and java #ContextConfiguration in integration test

I am trying to configure a Spring MVC Integration test using a combination of XML config and #Configuration annotated classes.
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#TestPropertySource({"/spring-security.properties",
"/rabbitmq-default.properties",
"/mongodb-default.properties",
"/webapp-override.properties"})
#ContextHierarchy({
#ContextConfiguration("classpath:**/security-config.xml"),
#ContextConfiguration(classes = RootConfig.class),
#ContextConfiguration(classes = SpringMvcConfig.class)
})
public class BaseConfiguredMvcIntegrationTest {
}
The java configurations are initialized correctly. The problem is although the "**/security-config.xml" file is found and parsed during initialization... all the spring security beans defined in there are never registered in the WebApplicationContext.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1301)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1047)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
So my question is how do you utilize both XML based and annotated based configuration in a Spring MVC Integration test?
I could change the spring security config to java/annotated based one... I would rather not do this. I find using the spring security namespace more readable and concise than using the java config.
Also, note this combined XML/Java configuration works perfectly fine in a non-test environment.
Spring v4.1.6
Spring Security v4.0.1
WebApplicationContext Config:
package com.gggdw.web.config;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.DispatcherServlet;
#Configuration
public class GGGWebInitializer implements WebApplicationInitializer {
public static final String SERVLET_NAME = "ggg";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(RootConfig.class);
// Manage the lifecycle of the root application context
servletContext.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(SpringMvcConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(SERVLET_NAME, new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
//Spring security config
FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter(
"securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"));
springSecurityFilterChain.addMappingForServletNames(null, false, SERVLET_NAME);
//springSecurityFilterChain.setAsyncSupported(true);
servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class);
}
}
RootConfig.class
#Configuration
#Import({WebPropertiesConfig.class, // loads all properties files on class path from resources folder
MongoConfig.class // init mongodb connection
})
#ImportResource({"classpath:**/security-config.xml"}) // spring security xml config (java config not as readable)
public class RootConfig {
}
security-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- <context:property-placeholder location="classpath:spring-security.properties" /> -->
<security:global-method-security pre-post-annotations="enabled" secured-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="permissionEvaluator"/>
</bean>
<bean id="permissionEvaluator"
class="com.my.local.package.security.GenericPermissionEvaluator">
</bean>
<!-- Configure Spring Security -->
<security:http auto-config="true" use-expressions="true" >
<security:form-login login-page="${spring.security.login-page}"
login-processing-url="${spring.security.login-processing-url}"
default-target-url="${spring.security.default-target-url}"
authentication-failure-url="${spring.security.authentication-failure-url}"
username-parameter="${spring.security.username-parameter}"
password-parameter="${spring.security.password-parameter}"
/>
<security:logout logout-url="${spring.security.logout-url}"
logout-success-url="${spring.security.logout-success-url}" />
<security:intercept-url pattern="/**" requires-channel="https" />
<security:intercept-url pattern="/s/**" access="isAuthenticated()" requires-channel="https" />
<security:custom-filter ref="log4JMDCFilter" after="SECURITY_CONTEXT_FILTER"/>
<security:access-denied-handler error-page="${spring.security.access-denied-handler-error-page}" />
<!-- <security:session-management invalid-session-url="${spring.security.invalid-session-url}"/>
2 types of invalid session, brand new user and a timeout of a previous logged in user
both need to be handled differently -->
</security:http>
<bean id="customUserDetailsService" class="com.my.local.package.CustomUserDetailsService" depends-on="userRepository"/>
<bean id="bCryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<!-- log4j filter to add userName and ipAddress into logging on a per request/thread basis -->
<bean id="log4JMDCFilter" class="com.my.local.package.filter.Log4JMDCFilter"/>
<security:authentication-manager>
<security:authentication-provider user-service-ref="customUserDetailsService">
<security:password-encoder ref="bCryptPasswordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
</beans>
UPDATE: upon further consideration and based on your latest feedback, the behavior you're experiencing might be the result of a bug that was introduced in Spring Framework 4.1.4 (see SPR-13075 for details).
Try downgrading to Spring Framework 4.1.3, and let me know if you still experience the undesired behavior.
note this combined XML/Java configuration works perfectly fine in a non-test environment.
How so?
Do you literally have three (3) contexts loaded in a hierarchy in production?
I doubt that. Rather, I assume you are somehow loading a single root WebApplicationContext from "classpath:**/security-config.xml" and RootConfig.class.
Thus, the most important question is: How are you configuring the root WebApplicationContext in production?
Once you have answered that, I can tell you how to achieve the same thing in your test configuration. ;)
Regards,
Sam (author of the Spring TestContext Framework)
Pay attention to the note from PathMatchingResourcePatternResolver:
Note that "classpath*:" when combined with Ant-style patterns will only work reliably with at least one root directory before the pattern starts, unless the actual target files reside in the file system. This means that a pattern like "classpath*:*.xml" will not retrieve files from the root of jar files but rather only from the root of expanded directories. This originates from a limitation in the JDK's ClassLoader.getResources() method which only returns file system locations for a passed-in empty String (indicating potential roots to search).

Using EJBs from a different JAR

I'm developing a JAX-WS WebService in JDeveloper 11.1.1.4 that should use EJBs from a JAR previously deployed to a WebLogic server. Both the WebService project and the EJB project are my own code, but I'd like to deploy them separately. For now I'm experimenting with the setup.
In the ExampleEJB project I have a bean ExampleBean that implements a remote interface Example.
#Remote
public interface Example {
public String doRemoteStuff();
}
#Stateless(name = "Example", mappedName = "ExampleApplication-ExampleEJB-Example")
public class ExampleBean implements Example {
public String doRemoteStuff() {
return "did remote stuff";
}
}
In that project, I have two deploy descriptors (ejb-jar.xml and weblogic-ejb-jar.xml):
ejb-jar.xml
<?xml version = '1.0' encoding = 'UTF-8'?>
<ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0" xmlns="http://java.sun.com/xml/ns/javaee">
<enterprise-beans>
<session>
<ejb-name>Example</ejb-name>
</session>
</enterprise-beans>
</ejb-jar>
weblogic-ejb-jar.xml
<?xml version = '1.0' encoding = 'UTF-8'?>
<weblogic-ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-ejb-jar http://www.bea.com/ns/weblogic/weblogic-ejb-jar/1.0/weblogic-ejb-jar.xsd"
xmlns="http://www.bea.com/ns/weblogic/weblogic-ejb-jar">
<weblogic-enterprise-bean>
<ejb-name>Example</ejb-name>
<stateless-session-descriptor/>
</weblogic-enterprise-bean>
</weblogic-ejb-jar>
Additionaly, I've created an EJB JAR deployment profile named example-ejb.jar and managed to deploy it to the server.
In the ExampleWS project I have an ExampleWebService:
#WebService(serviceName = "ExampleWebService")
public class ExampleWebService {
#EJB
Example example;
public String doStuff() {
return example.doRemoteStuff();
}
}
I added the ExampleEJB project dependency to this project (so it would compile). The only XML I have in this project is the web.xml used to describe the servlet. Also, I have the WebServices WAR file created automatically by jDeveloper when creating a WebService. Lastly, I created an EAR deployment profile named example-ws that only includes the WebServices WAR file in it's application assembly.
What do I need to do for this to work? Also, what would the procedure be if the ExampleEJB project was referenced from another project (say, AdditionalExampleEJB) that has additional beans that use ExampleBean? How would I reference the ExampleBean from there?
Thank you VERY MUCH for any help you can give me!
EDIT:
I've managed to reference the EJB from the WebService!
In the ExampleEJB project I modified the weblogic-ejb-jar.xml and now it looks like this:
weblogic-ejb-jar.xml
<?xml version = '1.0' encoding = 'UTF-8'?>
<weblogic-ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-ejb-jar http://www.bea.com/ns/weblogic/weblogic-ejb-jar/1.0/weblogic-ejb-jar.xsd"
xmlns="http://www.bea.com/ns/weblogic/weblogic-ejb-jar">
<weblogic-enterprise-bean>
<ejb-name>Example</ejb-name>
<stateless-session-descriptor>
<pool>
<max-beans-in-free-pool>10</max-beans-in-free-pool>
<initial-beans-in-free-pool>3</initial-beans-in-free-pool>
</pool>
<business-interface-jndi-name-map>
<business-remote>hr.example.Example</business-remote>
<jndi-name>ejb/example-ejb/Example</jndi-name>
</business-interface-jndi-name-map>
</stateless-session-descriptor>
</weblogic-enterprise-bean>
</weblogic-ejb-jar>
In the ExampleWS project I added a deployment descriptor weblogic.xml that looks like this:
weblogic.xml
<?xml version = '1.0' encoding = 'UTF-8'?>
<weblogic-web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-web-app http://www.bea.com/ns/weblogic/weblogic-web-app/1.0/weblogic-web-app.xsd"
xmlns="http://www.bea.com/ns/weblogic/weblogic-web-app">
<ejb-reference-description>
<ejb-ref-name>ExampleReference</ejb-ref-name>
<jndi-name>ejb/example-ejb/Example</jndi-name>
</ejb-reference-description>
</weblogic-web-app>
Note that the ExampleReference value and ejb/example-ejb/Example value are something I decided to enter - I think they is more or less a developer's choice.
Also, I referenced the EJB in my WebService using the ExampleReference value, so my ExampleWebService looks like this:
ExampleWebService
#WebService(serviceName = "ExampleWebService")
public class ExampleWebService {
#EJB(
name="ExampleReference"
)
Example example;
public String doStuff() {
return example.doRemoteStuff();
}
}
Lastly, in the deployment profile of ExampleWS (the WebServices.war) I added the dependency contributor and checked the interface Example.class element (NOT the ExampleBean.java that has the implementation).
Now, how would this work if the Example bean was referenced from another EJB project (not a WebService)?
So, for all those that encounter the same problem, I have solved it. There is no way to look up a remote EJB in EJB 3.0 other than using InitialContext.lookup("jndi/name"). Also, narrowing the object seems to help in some ClassCastException situations, so I tend to do it as a precaution. This is how I look up my EJBs:
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
public Object lookup (String jndiName, Class type) throws NamingException {
return PortableRemoteObject.narrow(InitialContext.doLookup(jndiName), type);
}
If using EJB 3.1, there is a way using #EJB(lookup = "jndi/name"), but since I'm not using this version, I cannot guarantee that this works.

List registered request mappings in the log at startup

I want to list all registered request mappings in the log at application startup (Spring MVC, log4j). Ideally I want to view two things for each entry: URL and corresponding controller's method.
What have I tried: I searched in corresponding documentation entry without success.
Please check this blogpost for more information about how to log Spring MVC mappings in your application, source blogpost.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
#Controller
public class EndpointDocController {
private final RequestMappingHandlerMapping handlerMapping;
#Autowired
public EndpointDocController(RequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}
#RequestMapping(value = "/endpointdoc", method = RequestMethod.GET)
public void show(Model model) {
model.addAttribute("handlerMethods",
this.handlerMapping.getHandlerMethods());
}
}
From spring's code (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping):
this.handlerMethods.put(mapping, newHandlerMethod);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
}
As you see the code is already there and mapped at INFO level (apache-commons-logging), so you should see every #RequestMapping by default, no matter if they are in #Controller or #RestController.
⚠ Because you ask for it, first make sure that a logger-implementation is available. If you see
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
At application start there is no logger-implementation! If this message occour, you have to decide what logger-implementation you like to use. The commonly most used are slf4j, log4j and jul.
Slf4j / Maven
Add this to the dependencies to see your output.
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.1</version> </dependency>
Why not use commons-logging?
Simply its a api to be used by others, not an implementation, not a single System.out is made by commons-logging.
Looks like starting from Spring 3.1 you need to activate info logging for org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(...).

Resources