2013-04-10 4 views
5

Ich versuche, LoggingFilter für Jersey in einem eingebetteten Jetty-Setup zu konfigurieren. Der Klebstoff-Code, der verwendet wird, ist wie folgt:LoggingFilter wird in Jersey ignoriert und eingebetteter Jetty

ServletContainer servletContainer = new ServletContainer(application); 
ServletHolder servletHolder = new ServletHolder(servletContainer); 
servletHolder.setInitParameter("com.sun.jersey.config.feature.Debug", "true"); 
servletHolder.setInitParameter("com.sun.jersey.config.feature.Trace", "true"); 
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", 
    "com.sun.jersey.api.container.filter.LoggingFilter"); 
servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", 
    "com.sun.jersey.api.container.filter.LoggingFilter"); 

Aber der Logging-Filter ist eigentlich ignoriert, und ich sehe keine relevanten Protokolle in der Konsole. Wie kann ich das machen? Getestet sowohl auf Jersey 1.x als auch auf 2.x.

Eine relevant answer beschreibt, wie dies unter Verwendung web.xml erreichen.

+0

Ihr Code scheint mit einer XML-Servlet-Konfiguration identisch zu sein, abgesehen von einem Detail - dem Servlet-Namen und der Servlet-Klasse. Vielleicht hast du diese Portion hier einfach nicht eingefügt. Haben Sie diese XML-Konfigurationslösung ausprobiert und bestätigt, dass sie tatsächlich in Ihrem Fall funktioniert? – Cebence

+0

Haben Sie die JDK-Protokollierung entsprechend konfiguriert? – skirsch

+0

@Cebence 'ServletHolder' dient als' web.xml'. Die Anwendung läuft und es funktioniert. – nobeh

Antwort

4

Ich denke, dies ist eine sehr feine Nuance des dokumentierten Verhalten von ServletContainer, wenn es nicht gar Fehler ist. Die ServletContainer docs zum Thema Init-Parameter lesen als:

Alle Initialisierungsparameter werden als Eigenschaften der erstellten ResourceConfig hinzugefügt.

Die Antwort ist dort versteckt. Insbesondere, wenn die ResourceConfig-Instanz nicht vom ServletContainer erstellt wird, werden die Servlet-Initialisierungsparameter nicht als Eigenschaften hinzugefügt und haben daher keinen Einfluss auf die Konfiguration Ihrer App. Wenn Sie Ihre eigene Application Instanz liefern, wie Sie mit dem new ServletContainer(application) hat, folgt die Initialisierung etwa diesen Kurs:

Ihr Code ruft den folgenden ServletContainer Konstruktor mit Application Beispiel:

public ServletContainer(Application app) { 
    this.app = app; 
} 

Der Behälter Ihre ServletContainer initialisiert als Teil eines typischen Servlet Lebenszyklus:

protected void init(WebConfig webConfig) throws ServletException { 
    webComponent = (app == null) 
      ? new InternalWebComponent() 
      : new InternalWebComponent(app); 
    webComponent.init(webConfig); 
} 

Es geht Ihre Application Instanz in den InternalWebComponent Konstruktor. Ein InternalWebComponent ist nur eine leichte Anpassung von WebComponent, so:

InternalWebComponent(Application app) { 
    super(app); 
} 

Anrufe:

public WebComponent(Application app) { 
    if (app == null) 
     throw new IllegalArgumentException(); 

    if (app instanceof ResourceConfig) { 
     resourceConfig = (ResourceConfig) app; 
    } else { 
     resourceConfig = new ApplicationAdapter(app); 
    } 
} 

Hier, da Sie eine Application Instanz direkt zur Verfügung gestellt wird ein ResourceConfig in einer der für Sie gebaut Zweige dieser Sekunde if.Unmittelbar nach dem Bau wird WebComponent.init() an der neuen Komponente aufgerufen (siehe oben unter ServletContainer.init(), woher wir kamen). Innerhalb dieser init() Aufruf ist, wo die "erstellt ResourceConfig" durch die Dokumente wird erstellt werden, aber in Ihrem Fall, existiert bereits eine, wie durch die Spur gezeigt, die wir folgten, um hier zu erhalten. Das heißt, die resourceConfig nicht null, so dass die wichtige Linie unten nicht ausgeführt:

public void init(WebConfig webConfig) throws ServletException { 
    ... 
    if (resourceConfig == null) 
     resourceConfig = createResourceConfig(config); 
    ... 
} 

Das createResourceConfig() Methode (noch in WebComponent) lautet wie:

private ResourceConfig createResourceConfig(WebConfig webConfig) 
     throws ServletException { 
    final Map<String, Object> props = getInitParams(webConfig); 
    final ResourceConfig rc = createResourceConfig(webConfig, props); 
    rc.setPropertiesAndFeatures(props); 
    return rc; 
} 

Sie in diesem Anruf sehen Das setPropertiesAndFeatures() wird verwendet, um die Initparameter des Servlets in die ResourceConfig Instanz zu kopieren. Leider ist dies der nur Ort, an dem dieser Aufruf gemacht wird, und in Ihrem Fall, Ausführung macht es hier nie, im Grunde wegen Ihrer Verwendung eines der nicht-Standard ServletContainer Konstruktoren.

Ich erwarte, dass die ursprünglichen Autoren ServletContainer mit nur einem Konstruktor no-arg geschrieben haben und die anderen zwei wurden später für die einfache Verwendung mit Servlet 3.0-Containern hinzugefügt, ohne zu erkennen, dass dieses Verhalten eingeführt wurde. Ansonsten würde ich erwarten, einige Erwähnung davon in den Dokumenten zu sehen.

So lange Geschichte kurz: entweder die Standard-ServletContainer Konstruktor verwenden oder einen Weg zu kümmern diesem Teil finden sich:

Map<String, Object> props = getInitParams(webConfig); 
rc.setPropertiesAndFeatures(props); 

Der erste Weg ist wahrscheinlich die einfachste. Zum Beispiel könnten Sie Ihre Application Klasse als init-Parameter angeben, auch, solange es gibt nichts, die Sie auffordert, es zu instanziieren vor der Zeit, wie zum Beispiel:

servletHolder.setInitParameter("javax.ws.rs.Application", "org.foo.MyApplication"); 

diese Weise der „normale“ Initialisierung Pfad genommen werden, was bedeutet, dass die WebComponent die ResourceConfig für Sie erstellt und die init-Parameter korrekt anwenden.

+0

Dieses 'ServletContainer> Servlet' Verhalten ist grundsätzlich inverson der Kontrolle (IoC) genau wie Spring's Dependency Injection - wenn Sie Ihre Bohnen autowirten möchten, dürfen Sie sie nicht selbst mit 'new' erstellen. Gleiches gilt für Servlets. – Cebence

+0

@Cebence: Ich glaube nicht, dass ich diesem Vergleich zustimme. Nehmen Sie zum Beispiel Spring's [DispatcherServlet] (http://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/web/servlet/DispatcherServlet.html), das kürzlich einen [neuen Konstruktor] bekommen hat (http://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/web/servlet/DispatcherServlet.html#DispatcherServlet(org.springframework.web.context.WebApplicationContext)), mit dem Sie ein vorhandener Spring-Kontext zur Verwendung in einer Servlet 3.0-Umgebung. Das funktioniert so, wie Sie es erwarten würden. Das tut es nicht. –

+0

Ja, aber ich habe nicht '3.0' gesagt. Man würde denken, nach 4-5 Jahren wäre die Umsetzung ausgereift. – Cebence

0

Ich denke, man könnte es falsch machen.

// Creating an instance of Jersey servlet, right? 
ServletContainer servletContainer = new ServletContainer(application); 

// Putting it in a container by reference. 
ServletHolder servletHolder = new ServletHolder(servletContainer); 

This page nicht das Servlet erstellen, wie Sie tun:

ServletHolder sh = new ServletHolder(WicketServlet.class); 

Auf diese Weise Jetty eine Instanz erstellt, und ruft Servlets init(). In Ihrem Fall müssen Sie init() nennen, aber ich bin nicht sicher, wo Sie die ServletConfiguration Instanz erhalten.

UPDATE: Sie sollten es auf diese Weise versuchen:

ServletHolder servletHolder = new ServletHolder(ServletContainer.class); 
    servletHolder.setInitParameter("javax.ws.rs.Application", "MyRESTApplication"); 
    servletHolder.setInitParameter("com.sun.jersey.config.feature.Debug", "true"); 
    servletHolder.setInitParameter("com.sun.jersey.config.feature.Trace", "true"); 
    servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", 
     "com.sun.jersey.api.container.filter.LoggingFilter"); 
    servletHolder.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", 
     "com.sun.jersey.api.container.filter.LoggingFilter"); 

    ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); 
    contextHandler.addServlet(servletHolder, "/services/*"); 
    server.setHandler(contextHandler);