ServletContext.log() not logging - gwt

Log output of my RemoteServiceServlet (GWT) is not shown in Logfiles or Stdout when using getServletContext().log("anything");
For dependency injection I use Google Guice. For my own log output I use slf4j-jdk14. I tried this in Tomcat 6 as well as in Jetty (GWT devmode).
To make it clear, my Servlet:
#Singleton
public class MyServiceServlet extends RemoteServiceServlet implements MyService {
private static final Logger log = LoggerFactory.getLogger(MyServiceServlet.class);
private final ADependency dep;
#Inject
public MyServiceServlet(ADependency dep) {
getServletContext().log("THIS IS NOT SHOWN IN MY LOGS");
log.error("THIS IS SHOWN IN MY LOGS");
this.dep = dep;
}
}
So, where can I find the missing log output or where can I configure the ServletContext-Log?

The ServletContext.log method behavior is container specific. The method I have used to make it consistent is to wrap the ServletConfig passed in through init() in order to create a wrapped ServletContext which uses our own provided logger (Slf4j in this case).
public class Slf4jServletConfigWrapper implements ServletConfig {
private final ServletConfig config;
private final Logger log;
public Slf4jServletConfigWrapper(Logger log, ServletConfig config) {
this.log = log;
this.config = config;
}
public ServletContext getServletContext() {
return new ServletContext() {
public void log(String message, Throwable throwable) {
log.info(message, throwable);
}
public void log(Exception exception, String msg) {
log.info(msg, exception);
}
public void log(String msg) {
log.info(msg);
}
...
Full Slf4jServletConfigWrapper.java code
In your Servlet override the init() method to use the ServletConfig wrapper
public void init(final ServletConfig config) throws ServletException {
super.init(new Slf4jServletConfigWrapper(log, config));
}

Related

#Inject constructor with parameters

I saw a method of using #inject annotation with parameter constructor. I found no use in #module in all parts of the project. I don't understand how this code injects or provides parameters in the constructor.
Can you help me analyze it?
Where is the datamanager provided?
In the whole project, #module + #provide is not used to provide datamanager. I only know that #inject can only annotate the parameterless constructor. I don't know where to instantiate the parameterless datamanager object. Thank you for your help
application:
public class Scallop extends Application {
private ApplicationComponent applicationComponent;
#Override
public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
application module:
#Module
public class ApplicationModule {
private Scallop application;
public ApplicationModule(Scallop application) { // 提供类的构造器,传入Applicaton
this.application = application;
}
#Provides
#Singleton
Application provideApplication() {
return application;
}
#Provides
#ApplicationContext
Context provideContext() {
return application;
}
#Provides
#Singleton
Retrofit provideRetrofit() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return retrofit;
}
#Provides
#Singleton
GankIOService provideGankIOService(Retrofit retrofit) {
return retrofit.create(GankIOService.class);
}
}
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
Application getApplication();
DataManager getDataManager();
}
```
one class:
#Singleton
public class DataManager {
private GankIOService gankIOService;
private PreferencesHelper preferencesHelper;
#Inject
public DataManager(GankIOService gankIOService, PreferencesHelper preferencesHelper) {
this.gankIOService = gankIOService;
this.preferencesHelper = preferencesHelper;
}
}
fragment module:
#FragmentScope
#Component(modules = FragmentModule.class, dependencies = ApplicationComponent.class)
public interface FragmentComponent {
void inject(HomeFragment homeFragment);
void inject(GanHuoPageFragment pageFragment);
void inject(XianDuFragment xianDuFragment);
void inject(XianDuPageFragment xianDuPageFragment);
void inject(PicturesFragment picturesFragment);
void inject(MoreFragment moreFragment);
}
#FragmentScope
#Documented
#Scope
#Retention(value = RetentionPolicy.RUNTIME)
public #interface FragmentScope {
}
```
here Can't understand constructor with parameter is #inject
public class GanHuoPagePresenter extends BasePresenter<GanHuoPageContract.View>
implements GanHuoPageContract.Presenter {
private DataManager dataManager;
private Disposable disposable;
#Inject
public GanHuoPagePresenter(DataManager dataManager) { // here here
this.dataManager = dataManager;
}
#Override
public void detachView() {
super.detachView();
if (disposable != null) {
disposable.dispose();
}
}
#Override
public void getGanHuo(String category, final int page) {
final List<GanHuo> ganHuoList = new ArrayList<>();
Observable<BaseResponse<GanHuo>> observable = dataManager.getGanHuo(category, page);
disposable = observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.concatMap(new Function<BaseResponse<GanHuo>, ObservableSource<GanHuo>>() {
#Override
public ObservableSource<GanHuo> apply(#NonNull BaseResponse<GanHuo> ganHuoBaseResponse)
throws Exception {
return Observable.fromIterable(ganHuoBaseResponse.getResults());
}
}).filter(new Predicate<GanHuo>() {
#Override
public boolean test(#NonNull GanHuo ganHuo) throws Exception {
return !ganHuo.getType().equals("福利");
}
}).subscribe(new Consumer<GanHuo>() {
#Override
public void accept(GanHuo ganHuo) throws Exception {
ganHuoList.add(ganHuo);
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
getView().showError(throwable.getMessage());
}
}, new Action() {
#Override`enter code here`
public void run() throws Exception {
getView().showList(ganHuoList, page);
}
});
}
}
This is how it is used in V in MVP mode:
#Inject GanHuoPagePresenter presenter
That's constructor injection. By marking a constructor with #Inject Dagger knows about the object and can create it when needed. There's no need for modules, e.g. the following is a valid Dagger setup to create some Foo.
public class Foo {
#Inject
public Foo() {}
}
#Component
interface MyComponent {
Foo getFoo();
}
That's not true that #Inject can only annotate the parameterless constructor. From documentation
Injectable constructors are annotated with #Inject and accept zero or more dependencies as arguments.
I found "your" project on Github so let's see where dependencies for GanHuoPagePresenter come from.
#Inject
public GanHuoPagePresenter(DataManager dataManager) {
this.dataManager = dataManager;
}
#Inject
public DataManager(GankIOService gankIOService,PreferencesHelper preferencesHelper){
// gankIOService is provided by ApplicationModule and preferencesHelper uses constructor injection
this.gankIOService = gankIOService;
this.preferencesHelper = preferencesHelper;
}
#Inject
public PreferencesHelper(#ApplicationContext Context context){
// context is provided again by ApplicationModule
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
}

Resteasy 3 #Context HttpServletRequest always null

We were using Resteasy 2 but we are upgrading to Resteasy 3 and the HttpServletRequest injection is always null.
Our modified security interceptor/filter that looks like:
#Provider
#ServerInterceptor
#Precedence("SECURITY")
public class SecurityInterceptor implements ContainerRequestFilter, ContainerResponseFilter {
#Context
private HttpServletRequest servletRequest;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Need access to "servletRequest" but it is always null
if (!isTokenValid(pmContext, method)) {
requestContext.abortWith(ACCESS_DENIED);
}
}
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
// post processing
}
}
And the application class looks like:
#ApplicationPath("/")
public class RestApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> empty = new HashSet<Class<?>>();
public RestApplication() {
// Interceptors
this.singletons.add(new SecurityInterceptor());
// Services
this.singletons.add(new MyService());
}
public Set<Class<?>> getClasses() {
return this.empty;
}
public Set<Object> getSingletons() {
return this.singletons;
}
}
Sample API:
#Path("/test")
public class MyService extends BaseService {
#Context HttpServletRequest servletRequest;
#GET
#Path("/hello")
#Produces(MediaType.APPLICATION_JSON)
public Response hello() {
// Need access to HttpServletRequest but it's null
return Response.ok("hello").build();
}
}
However, looking at this and this posts, I don't see HttpServletRequest injection provider.
This leads me to believe that I may need an additional plugin. This is what is installed:
jose-jwt
resteasy-atom-provider
resteasy-cdi
resteasy-crypto
resteasy-jackson2-provider
resteasy-jackson-provider
resteasy-jaxb-provider
resteasy-jaxrs
resteasy-jettison-provider
resteasy-jsapi
resteasy-json-p-provider
resteasy-multipart-provider
resteasy-spring
resteasy-validator-provider-11
resteasy-yaml-provider
Any ideas?
Based on #peeskillet suggestion, modifying to return new class instances instead of singletons resolved my issue.
Thus my modified javax.ws.rs.core.Application file looks like:
#ApplicationPath("/")
public class RestApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public RestApplication() {
// Interceptors
this.classes.add(SecurityInterceptor.class);
// Services
this.classes.add(MyService.class);
}
public Set<Class<?>> getClasses() {
return this.classes;
}
public Set<Object> getSingletons() {
return this.singletons;
}
}
You could use the SecurityInterceptor's constructor to get these values:
///...
private HttpServletRequest request;
private ServletContext context;
public SecurityInterceptor(#Context HttpServletRequest request, #Context ServletContext context) {
this.request = request;
this.context = context;
}
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// The "servletRequest" won't be null anymore
if (!isTokenValid(pmContext, method)) {
requestContext.abortWith(ACCESS_DENIED);
}
}
///...
This'll solve your problem

How to chain jax-rs base64 encoder and gzip

I would like to chain a base64 encoder and gzip in jax-rs via interceptors.
The encoder is implemented as follows:
#EncryptPayload
#Provider
#Priority(Priorities.ENTITY_CODER)
public class EncryptPayloadInterceptor implements WriterInterceptor {
private Logger logger;
#Inject
public EncryptPayloadInterceptor(Logger logger) {
this.logger = logger;
}
public EncryptPayloadInterceptor() {
super();
}
#Override
public void aroundWriteTo(WriterInterceptorContext writerInterceptorContext) throws IOException, WebApplicationException {
logger.error("Calling EncryptPayload Interceptor: ");
final OutputStream outputStream = writerInterceptorContext.getOutputStream();
writerInterceptorContext.getHeaders().putSingle("X-ENCRYPTED", "true");
writerInterceptorContext.setOutputStream(new Base64OutputStream((outputStream)));
writerInterceptorContext.proceed();
}
}
The gzip part is implemented as follows:
#Provider
#Priority(Priorities.USER)
public class GZIPWriterInterceptor implements WriterInterceptor {
private Logger logger;
#Inject
public GZIPWriterInterceptor(Logger logger) {
this.logger = logger;
}
public GZIPWriterInterceptor() {
super();
}
#Override
public void aroundWriteTo(WriterInterceptorContext writerInterceptorContext) throws IOException, WebApplicationException {
logger.error("Calling GZIPWriter Interceptor: ");
final OutputStream outputStream = writerInterceptorContext.getOutputStream();
writerInterceptorContext.setOutputStream(new GZIPOutputStream(outputStream));
writerInterceptorContext.getHeaders().putSingle("Content-Encoding", "gzip");
writerInterceptorContext.proceed();
}
}
When disabling gzip as a provider it works nicely. When enabling the provider GZIP I receive the following error within jersey:
LOGGER.log(Level.SEVERE, LocalizationMessages.ERROR_COMMITTING_OUTPUT_STREAM(), e);
First the encoding is called and after that the gzip is called. It seems that Base64 might close the stream.
Any help highly appreciated.

How to get MDC logging working for Spring Batch

In Spring Batch it would be great to keep track of the execution thread through logging. However, MDC does not seem to work.
MDC.put("process", "batchJob");
logger.info("{}; status={}", getJobName(), batchStatus.name());
Anyone got MDC working in Spring Batch?
I solved it by adding a JobExecutionListener like that:
public class Slf4jBatchJobListener implements JobExecutionListener {
private static final String DEFAULT_MDC_UUID_TOKEN_KEY = "Slf4jMDCFilter.UUID";
private final Logger logger = LoggerFactory.getLogger(getClass());
public void beforeJob(JobExecution jobExecution) {
String token = UUID.randomUUID().toString().toUpperCase();
MDC.put(DEFAULT_MDC_UUID_TOKEN_KEY, token);
logger.info("Job {} with id {} starting...", jobExecution.getJobInstance().getJobName(), jobExecution.getId());
}
public void afterJob(JobExecution jobExecution) {
logger.info("Job {} with id {} ended.", jobExecution.getJobInstance().getJobName(), jobExecution.getId());
MDC.remove(DEFAULT_MDC_UUID_TOKEN_KEY);
}
}
Because some jobs are multi-threaded, I had to add also a TaskDecorator in order to copy the DMC from the parent thread to the subthread like this:
public class Slf4JTaskDecorator implements TaskDecorator {
#Override
public Runnable decorate(Runnable runnable) {
Map<String, String> contextMap = MDC.getCopyOfContextMap();
return () -> {
try {
MDC.setContextMap(contextMap);
runnable.run();
} finally {
MDC.clear();
}
};
}
}
Set the TaskDecorator to the TaskExecutor:
#Bean
public TaskExecutor taskExecutor(){
SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("spring_batch");
taskExecutor.setConcurrencyLimit(maxThreads);
taskExecutor.setTaskDecorator(new Slf4JTaskDecorator());
return taskExecutor;
}
And lastly, update the logging pattern in properties:
logging:
pattern:
level: "%5p %X{Slf4jMDCFilter.UUID}"

Junit to test restful service

I have written a junit to test my rest service offline.The junit for my restful controller extends AbstractControllerTestSupport which is used to create the dispatcherservletinstance.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=MockWebContextLoader.class, locations={"/rest-servlet- test.xml"})
public abstract class AbstractControllerTestSupport extends TestCase {
private static DispatcherServlet dispatcherServlet;
....
public static DispatcherServlet getServletInstance() {
if(null == dispatcherServlet) {
dispatcherServlet = new DispatcherServlet() {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
return MockWebContextLoader.getInstance();
}
};
System.out.println("dispatcher:"+dispatcherServlet.getContextConfigLocation()+":"+dispatcherServlet.getWebApplicationContext());
try {
dispatcherServlet.init(new MockServletConfig());
} catch (ServletException se) {
System.out.println("Exception"+se.getMessage());
}
}
return dispatcherServlet;
}
Following is my loader class.
public class MockWebContextLoader extends AbstractContextLoader {
public static final ServletContext SERVLET_CONTEXT = new MockServletContext(
"/mHealthAPIs", new FileSystemResourceLoader());
private final static GenericWebApplicationContext webContext = new GenericWebApplicationContext();
protected BeanDefinitionReader createBeanDefinitionReader(
final GenericApplicationContext context) {
return new XmlBeanDefinitionReader(context);
}
public final ConfigurableApplicationContext loadContext(
final String... locations) throws Exception {
SERVLET_CONTEXT.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
webContext);
webContext.setServletContext(SERVLET_CONTEXT);
createBeanDefinitionReader(webContext).loadBeanDefinitions(locations);
AnnotationConfigUtils.registerAnnotationConfigProcessors(webContext);
webContext.refresh();
webContext.registerShutdownHook();
return webContext;
}
public static WebApplicationContext getInstance() {
return webContext;
}
protected String getResourceSuffix() {
return "-context.xml";
}
the test runs fine with spring version 3.0 .However if I shift to spring 3.2.x it gives me following error "The type MockWebContextLoader must implement the inherited abstract method SmartContextLoader.loadContext(MergedContextConfiguration)" .This is because in 3.2.2 "AbstractContextLoader" implements "SmartContextLoader" .
Can you provide me with the work around?
Got the solution:I changed the MockWebContextLoader class as follows.
public class MockWebContextLoader extends AbstractContextLoader {
public static final ServletContext SERVLET_CONTEXT = new MockServletContext(
"/mHealthAPIs", new FileSystemResourceLoader());
private final static GenericWebApplicationContext webContext = new GenericWebApplicationContext();
protected BeanDefinitionReader createBeanDefinitionReader(
final GenericApplicationContext context) {
return new XmlBeanDefinitionReader(context);
}
#Override
public ApplicationContext loadContext(MergedContextConfiguration arg0)
throws Exception {
SERVLET_CONTEXT.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
webContext);
webContext.setServletContext(SERVLET_CONTEXT);
createBeanDefinitionReader(webContext).loadBeanDefinitions(
arg0.getLocations());
AnnotationConfigUtils.registerAnnotationConfigProcessors(webContext);
webContext.refresh();
webContext.registerShutdownHook();
return webContext;
}
public static WebApplicationContext getInstance() {
return webContext;
}
protected String getResourceSuffix() {
return "-context.xml";
}
public final ConfigurableApplicationContext loadContext(
final String... locations) throws Exception {
return null;
}
}