I am working on an application consisting of several backend services and an external client. The entire application is written in Java, and we use the Apache TomEE web server to run it.
Backend services provide several APIs and contain several controllers. Some of these APIs are available to an external client, and some of them are designed for internal communication between backend services.
Logging is very important for this application. There is a requirement that the registration system always be initialized before the start of normal operations (to ensure complete traceability). The application uses a secure logging system for which it is necessary to initialize the logbook (logs are blocked with this key to prevent unauthorized use of logs). It is also necessary that the registration key is uploaded to each service. Each core service has an endpoint for receiving a registration key.
There is a chicken or egg problem. The application must be running to receive the key, but also the application should not fully function until the key is received.
To meet the requirements, we consider the following startup procedure:
- Starting backend services in a reduced mode of operation, in which the only available endpoint in each service is the one that accepts the incoming key.
- After receiving the key and initializing the logging system, then activate the rest of the endpoints and begin the usual operations.
Is there a standard way to activate endpoints to facilitate this startup process? or in any case, control access to endpoints.
Additional information: the controller classes in the application do not apply to other classes and are only decorated with @Path and @Stateless .
Update 1
I followed the approach to using a filter (as suggested by Bogdan below). I created a filter that captures all requests. The application starts correctly. The init() method is called in the filter class. But when I access the /installkey , an error occurs.
It looks like the doFilter(ServletRequest, ServletResponse, FilterChain) method doFilter(ServletRequest, ServletResponse, FilterChain) is being called, and my code detects that the request for the endpoint is /installkey . But when calling, an error occurs: filterChain.doFilter(request, response); .
I checked, and I know that the filterChain variable filterChain not null , however, inside the doFilter(ServletRequest, ServletResponse, FilterChain) method doFilter(ServletRequest, ServletResponse, FilterChain) something goes wrong and I can not debug it.
Perhaps I did not initialize something that needs to be initialized.
I have added the result that I get below.
Now I have the following in web.xml :
<filter> <filter-name>myFilter</filter-name> <filter-class>com.company.filter.LoggingFilter</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter-name> <url-pattern>*</url-pattern> </filter-mapping>
And the following class:
public class LoggingFilter implements Filter { @Override public void init(final FilterConfig filterConfig) throws ServletException { } public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException { String url = ""; if (request instanceof HttpServletRequest) { url = ((HttpServletRequest) request).getRequestURL().toString(); } if (url.endsWith("/installkey/")) { filterChain.doFilter(request, response); return; } else if (loggerConfig.isInitialized()) { filterChain.doFilter(request, response); return; } } public void destroy() { System.out.println("XXXXXXXXXXX Running destroy"); } }
But I get the following error:
Jan 19, 2016 10:42:25 AM org.apache.catalina.core.StandardWrapperValve invoke SEVERE: Servlet.service() for servlet [default] in context with path [/vw-ws-rest] threw exception [Error processing webservice request] with root cause java.lang.NullPointerException at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:240) at org.apache.openejb.server.cxf.rs.CxfRsHttpListener.doInvoke(CxfRsHttpListener.java:227) at org.apache.tomee.webservices.CXFJAXRSFilter.doFilter(CXFJAXRSFilter.java:94) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at com.company.filter.LoggingFilter.doFilter(LoggingFilter.java:63) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:44) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745)
Update 2
As an alternative, I tried using the JAX-RS name binding, as suggested by Cassio Mazzotchi Molin.
I created an interface:
import javax.ws.rs.NameBinding; @NameBinding @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD }) public @interface TemporarilyDisabled { }
And I created a filter class as follows:
@Provider @TemporarilyDisabled public class LoggingFilter implements ContainerRequestFilter { @Override public void filter(final ContainerRequestContext requestContext) throws IOException { System.out.println("in filter method!"); } }
And updated the resource controller class as follows:
@Path("installkey") @Stateless(name = "vw-installKeyResource") public class VwInstallKeyResource { @Inject private Logger LOG; @EJB
This application uses Java EE 6, which I cannot update. To test this approach, I had to add the following dependency to the application:
<dependency> <groupId>javax.ws.rs</groupId> <artifactId>javax.ws.rs-api</artifactId> <version>2.0</version> </dependency>
The code all compiles fine, and the application starts fine.
But when I access the endpoint (the endpoint that should be caught by the filter), then the filter code is not executed (I never see the print statement in the filter method), and the endpoint just executes as usual.
For some reason, the filter does not capture the request.
I don't know if the problem is that the endpoint is POST. Alternatively, maybe JAX-RS does not find the filter class, it is decorated with @provider, but I do not know if I need to register the filter in any other way.