I'm embedding Jetty in a similar manner as described here. When the RequestLogHandler can't open the specified logfile, it throws an exception which is unfortunately caught by org.eclipse.jetty.server.Server and swallowed (but logged first, at least). This means that there's no obvious way for me to tell if the log handler was started correctly.
Is there a way that I'm missing to detect when a handler couldn't start?
This idea is based on the implementation of WebAppContext where you can use WebAppContext.getUnavailableException() to determine whether the context was initialized successfully.
Simply replace the default implementation of Server and Context with your own:
public static class MyContext extends Context {
private Exception _exception;
#Override
protected void doStart() throws Exception {
try {
super.doStart();
} catch (final Exception e) {
_exception = e;
}
}
#Override
protected void doStop() throws Exception {
try {
super.doStop();
} finally {
_exception = null;
}
}
public Exception getException() {
return _exception;
}
}
public static class MyServer extends Server implements InitializingBean {
public void afterPropertiesSet() throws Exception {
start();
for (final Handler h : getHandlers()) {
if (h instanceof MyContext) {
final MyContext c = (MyContext) h;
if (c.getException() != null) {
throw new RuntimeException("failed to init context " + c.getDisplayName(),
c.getException());
}
}
}
}
}
In your beans.xml, simply replace org.mortbay.jetty.Server (and remove init-method="start") and org.mortbay.jetty.servlet.Context with your own implementations.
This code is for Jetty 6 though (as is the example you linked to), as that's what I have around. I didn't test it though, but it's pretty much the same as we are successfully using in conjunction with WebAppContext. In order to extend this to RequestLogHandler, you could either do the same for just any handler you are using or create a decorator to wrap any handler. You may want to look at org.mortbay.jetty.handler.HandlerWrapper for this purpose.
How about modifying the jetty code? You could add some simple println statements in strategic places in the RequestLogHandler which would indicate to you whether or not the handler was started.
Related
I did all the setup for error handling
#PostConstruct
public void addStateMachineInterceptor() {
stateMachine.getStateMachineAccessor().withRegion().addStateMachineInterceptor(interceptor);
stateMachine.getStateMachineAccessor().doWithRegion(errorinterceptor);
}
created interceptor to handle error:
#Service
public class OrderStateMachineFunction<T> implements StateMachineFunction<StateMachineAccess<String, String>> {
#Override
public void apply(StateMachineAccess<String, String> stringStringStateMachineAccess) {
stringStringStateMachineAccess.addStateMachineInterceptor(
new StateMachineInterceptorAdapter<String, String>() {
#Override
public Exception stateMachineError(StateMachine<String, String> stateMachine,
Exception exception) {
// return null indicating handled error
return exception;
}
});
}
}
But I can't see the call going into OrderStateMachineFunction, when we throw the exception from the action.
And after that state machine behave some wired way, like it stops calling preStateChange method after this.stateMachine.sendEvent(eventData);. It seems state machine breaks down after you throw the exception from the action.
#Service
public class OrderStateMachineInterceptor extends StateMachineInterceptorAdapter {
#Override
public void preStateChange(State newState, Message message, Transition transition, StateMachine stateMachine) {
System.out.println("Manish");
}
}
After trying few bit, I have seen that if I comment the resetStateMachine, it works as expected, but without that I am not able to inform the currentstate to state machine:
public boolean fireEvent(Object data, String previousState, String event) {
Message<String> eventData = MessageBuilder.withPayload(event)
.setHeader(DATA_KEY, data)
.build();
this.stateMachine.stop();
// this.stateMachine
// .getStateMachineAccessor()
// .withRegion()
// .resetStateMachine(new DefaultStateMachineContext(previousState, event, eventData.getHeaders(), null));
this.stateMachine.start();
return this.stateMachine.sendEvent(eventData);
}
Not sure if you still need this. But I bumped into similar issue. I wanted to propagate exception from state machine to the caller. I implemented StateMachineInterceptor. And inside the state machine transition functions I am setting:
try
{
..
}
catch (WhateverException e)
{
stateMachine.setStateMachineError(e);
throw e;
}
Then inside the interceptor's stateMachineError method, I have added the Exception in the extendedState map:
public Exception stateMachineError(StateMachine<States, Events> stateMachine, Exception exception)
{
stateMachine.getExtendedState().getVariables().put("ERROR", exception);
logger.error("StateMachineError", exception);
return exception;
}
Inside resetStateMachine I have added the interceptor to the statemachine.
a.addStateMachineInterceptor(new LoggingStateMachineInterceptor());
Then when I am calling the sendEvent method, I am doing this:
if (stateMachine.hasStateMachineError())
{
throw (Exception) svtStateMachine.getExtendedState().getVariables().get("ERROR");
}
This is returning the WhateverException right to the caller. Which in my case is a RestController.
The approach I'm taking here is combining the extended state to store errors with an error action.
If an expected exception happens in your action and any class inside of it, I include it in the extended state context
context.getExtendedState().getVariables().put("error", MyBussinessException);
then, on my error action (configured like this)
.withExternal()
.source(State.INIT)
.target(State.STARTED)
.action(action, errorAction)
.event(Events.INIT)
Outside machine context, I always check if that field is present or not, and translate it to proper response code.
If any exception is thrown from action, error action will be triggered. There you can check known errors (and let them bubble up), or include a new errors (if that was unexpected)
public class ErrorAction implements Action<States, Events> {
#Override
public void execute(StateContext<States, Events> context) {
if(!context.getExtendedState().getVariables().containsKey("error")
context.getExtendedState().getVariables().put("error", new GenericException());
}
}
I have a fully working spring and vaadin application based off spring boot. The application class has now been modified to create a custom servlet so I can use both touchkit and spring within the project as such.
I have been following this git project to perform this:git project example
public class SmartenderApplication {
public static void main(String[] args) {
SpringApplication.run(SmartenderApplication.class, args);
}
#Bean
public VaadinServlet vaadinServlet() {
return new SpringAwareTouchKitServlet();
}}
I modified the custom servlet to follow the vaadin docs for using a UI provider to choose between the touchkit UI and the browswer fallback UI as so
public class SpringAwareTouchKitServlet extends SpringVaadinServlet {
TouchKitSettings touchKitSettings;
MyUIProvider prov = new MyUIProvider();
#Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
getService().addSessionInitListener(
new SessionInitListener() {
#Override
public void sessionInit(SessionInitEvent event)
throws ServiceException {
event.getSession().addUIProvider(prov);
}
});
touchKitSettings = new TouchKitSettings(getService());
}
}
class MyUIProvider extends UIProvider {
#Override
public Class<? extends UI>
getUIClass(UIClassSelectionEvent event) {
String ua = event.getRequest()
.getHeader("user-agent").toLowerCase();
if ( ua.toLowerCase().contains("ios")) {
return myTouchkitUI.class;
} else {
return myUI.class;
}
}
}
My application works when I do not call this section of code to choose a UI provider. But it will always go to a touchkit UI. :
getService().addSessionInitListener(
new SessionInitListener() {
#Override
public void sessionInit(SessionInitEvent event)
throws ServiceException {
event.getSession().addUIProvider(prov);
}
});
My issue is that although it will choose between which UI class to return as soon as it begins to progress through the chosen UI code it passes back null objects that were originally autowired through spring. Seeing as this works when i dont choose a UI and just goes for touchkit, im assuming it must be somewhere in my UI provider choice code thats stopping the Spring functionality from allowing my classes to autowire, etc?
Well, the UIProvider is supposed to manage UI instances. Furthermore, since you're using Spring (Boot or not) it should retrieve beans from the Spring context instead of creating the instances itself when one is necessary:
UIProvider / DefaultUIProvider:
public UI createInstance(UICreateEvent event) {
try {
return event.getUIClass().newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Could not instantiate UI class", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Could not access UI class", e);
}
}
Thus, I'd say that instead of extending the simple UIProvider (or rather the DefaultUIProvider) you should extend the SpringUIProvider, which retrieves instances from your app's Spring context, so the automagic will begin to happen again.
SpringUIProvider:
#Override
public UI createInstance(UICreateEvent event) {
final Class<UIID> key = UIID.class;
final UIID identifier = new UIID(event);
CurrentInstance.set(key, identifier);
try {
logger.debug(
"Creating a new UI bean of class [{}] with identifier [{}]",
event.getUIClass().getCanonicalName(), identifier);
return webApplicationContext.getBean(event.getUIClass());
} finally {
CurrentInstance.set(key, null);
}
}
I am using netty for developing my server.
I am also implementing the Idle state handling in netty.
I got it working but an issue I recently found out.
I can't access the channel context attributes inside the userEventTriggered method.
here is my code and can anybody tell me why it is not possible.
I am setting it like
public static final AttributeKey<Agent> CLIENT_MAPPING = AttributeKey.valueOf("clientMapping");
...
ctx.attr(CLIENT_MAPPING).set(agent);
and inside handler, I am getting the value like (this is working perfectly)
Agent agent = ctx.attr(CLIENT_MAPPING).get();
But inside userEventTriggered it is returning null. (I am sure that it is set before this function is being called.)
public class Server
{
...
public void run() throws Exception
{
...
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).
channel(NioServerSocketChannel.class).
childHandler(new SslServerInitializer());
...
}
}
class SslServerInitializer extends ChannelInitializer<SocketChannel>
{
#Override
public void initChannel(SocketChannel ch) throws Exception
{
ChannelPipeline pipeline = ch.pipeline();
....
pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, Integer.parseInt(Main.configurations.get("netty.idleTimeKeepAlive.ms"))));
pipeline.addLast("idleTimeHandler", new ShelloidIdleTimeHandler());
}
}
class ShelloidIdleTimeHandler extends ChannelDuplexHandler
{
#Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
{
if (evt instanceof IdleStateEvent)
{
try
{
// This I am getting null, but I confirmed that I set the attribute from my handler and is accessible inside handler.
Agent agt = ctx.attr(WebSocketSslServerHandler.CLIENT_MAPPING).get();
ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":\"PING\", \"userId\": \"" + agt.getUserId() + "\"}"));
}
catch (Exception ex)
{
ctx.disconnect();
ex.printStackTrace();
}
}
}
}
Are you sure you set and get it in the same ChannelHandler? If you want to set and get it in different ChannelHandler you need to use Channel.attr(...)
I have written a huge Web-Application and 'forgot' to include logging (I only print the errors with the standard e.printStackTrace() method).
My question is, if there is any method to auto-log (getLogger.LOG(SEVERE,"...")) any thrown exception?
maybe with a custom exception-factory like in exceptionFactory JSF?
I want to log every thrown exception with my logger, e.g. before the program enters the catch-block, the exception has to be logged already:
try{
...
} catch(Exception1 e){
//Exception must have been already logged here (without adding getLogger().LOG(...) every time)
System.out.println(e.printStackTrace());
} catch(Exception2 e){
//Exception must have been already logged here (without adding getLogger().LOG(...) every time)
System.out.println(e.printStackTrace());
}
Take a look at aspect oriented programming which can insert logging code at runtime for your favorite logging framework. The JDK includes the java.lang.instrument package which can insert bytecodes during classloading to perform your logging.
Otherwise, you can install a servlet Filter as the top most filter in the call chain which will catch most of your exceptions.
public class LogFilter implements javax.servlet.Filter {
private static final String CLASS_NAME = LogFilter.class.getName();
private static final Logger logger = Logger.getLogger(CLASS_NAME);
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
logger.entering(CLASS_NAME, "doFilter", new Object[]{request, response});
try {
chain.doFilter(request, response);
} catch (IOException | ServletException | RuntimeException | Error ioe) {
logger.log(Level.SEVERE, "", ioe);
throw ioe; //Keep forwarding.
} catch (Throwable t) {
logger.log(Level.SEVERE, "", t);
throw new ServletException(t);
}
logger.exiting(CLASS_NAME, "doFilter");
}
#Override
public void destroy() {
}
}
You can set uncaught exception handler for main thread and every other you create using Thread.setUncaughtExceptionHandler() method and do all the required logging there.
I am now also in front of new larger project and interested in elimination of not necessary code to be produced. First I wanted to log every entry and exit from method including input and output data. In my case of event driven architecture I am pushing these data to elastic and analyse continuously method processing timeouts, that is lot of code lines. So I handled this with AspectJ. Very nice example of this is here:
http://www.baeldung.com/spring-performance-logging
Same applies for auto Error logging, here is dummy example which I will extend to work with slf4j, but these are details:
public aspect ExceptionLoggingAspect {
private Log log = LogFactory.getLog(this.getClass());
private Map loggedThrowables = new WeakHashMap();
public pointcut scope(): within(nl.boplicity..*);
after() throwing(Throwable t): scope() {
logThrowable(t, thisJoinPointStaticPart,
thisEnclosingJoinPointStaticPart);
}
before (Throwable t): handler(Exception+) && args(t) && scope() {
logThrowable(t, thisJoinPointStaticPart,
thisEnclosingJoinPointStaticPart);
}
protected synchronized void logThrowable(Throwable t, StaticPart location,
StaticPart enclosing) {
if (!loggedThrowables.containsKey(t)) {
loggedThrowables.put(t, null);
Signature signature = location.getSignature();
String source = signature.getDeclaringTypeName() + ":" +
(enclosing.getSourceLocation().getLine());
log.error("(a) " + source + " - " + t.toString(), t);
}
}
}
I would be happy to hear what else is good example of boiler plate code reduction. I of course use Loombok which does superior task...
NOTE: do not reinvent wheel, so look here as other people collected usefull AOP to be reused in your project out of the box :-)) open source is great community: https://github.com/jcabi/jcabi-aspects
i have a problem is:
java.lang.Exception: ServletConfig has not been initialized
I searched for it nearly 2 days but i did not have a solution for me. Every one had said that
super.init(config) must be used. I have tried this, but there is nothing change for me.
My init method;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
AppServiceServlet service = new AppServiceServlet();
try {
service.getir();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
AutoCheckStatus.autoCheckStatus(600000);
}
and my AppServiceServlet;
public List<SswAppServiceDto> getir() throws Exception {
try {
final WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(this
.getServletContext());
setiAppServiceBusinessManager((IAppServiceBusinessManager) context.getBean(BEAN_ADI));
List<SswAppService> result = getiAppServiceBusinessManager().getir();
List<SswAppServiceDto> list = DtoConverter.convertSswAppServiceDto(result);
for (int i = 0; i < result.size(); i++) {
AppService appService = new AppService();
appService.setServiceName(result.get(i).getName());
appService.setUid(result.get(i).getServiceUid());
appService.setHost(result.get(i).getHost());
appService.setPort((int) result.get(i).getPort());
SystemConfiguration.appServiceList.put(appService.getUid(), appService);
}
return list;
} catch (RuntimeException e) {
throw new Exception(e.getMessage(), e.getCause());
}
}
The exception is thrown in this line;
final WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
in AppServiceServlet and says:
java.lang.Exception: ServletConfig has not been initialized.
Pls help.
This call:
AppServiceServlet service = new AppServiceServlet();
Instantiates a servlet instance via new, which circumvents the normal, container managed creation of a servlet. As such, critical class variables (for example, the servlet config) don't get properly initialized.
Later on, you are making a call to getServletContext, which simply redirects to getServletConfig().getServletContext(), but because the servlet configuration was never completed you get an exception.
Infact, calling new on a servlet the way you are is non-compliant with the specification - servlets are supposed to be maintained by the web app container. The proper way to launch a startup servlet is either via configuration in your web.xml file, or via annotation.