View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2015-2016 ForgeRock AS.
15   */
16  
17  package org.forgerock.audit;
18  
19  import static org.forgerock.audit.AuditServiceBuilder.newAuditService;
20  import static org.forgerock.audit.json.AuditJsonConfig.getJson;
21  import static org.forgerock.audit.json.AuditJsonConfig.registerHandlerToService;
22  import static org.forgerock.http.routing.RouteMatchers.requestUriMatcher;
23  
24  import java.io.IOException;
25  import java.io.InputStream;
26  
27  import org.forgerock.audit.events.handlers.buffering.BatchPublisherFactory;
28  import org.forgerock.audit.events.handlers.buffering.BatchPublisherFactoryImpl;
29  import org.forgerock.audit.json.AuditJsonConfig;
30  import org.forgerock.http.Client;
31  import org.forgerock.http.Handler;
32  import org.forgerock.http.HttpApplication;
33  import org.forgerock.http.HttpApplicationException;
34  import org.forgerock.http.handler.HttpClientHandler;
35  import org.forgerock.http.io.Buffer;
36  import org.forgerock.http.routing.Router;
37  import org.forgerock.http.routing.RoutingMode;
38  import org.forgerock.json.JsonValue;
39  import org.forgerock.json.resource.Resources;
40  import org.forgerock.json.resource.ServiceUnavailableException;
41  import org.forgerock.json.resource.http.CrestHttp;
42  import org.forgerock.util.Factory;
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
45  
46  /**
47   * Crest Application that instantiates the AuditService on the crest router.
48   */
49  public final class AuditHttpApplication implements HttpApplication {
50  
51      private static final Logger logger = LoggerFactory.getLogger(AuditHttpApplication.class);
52      /** Audit event handlers config location. */
53      public static final String AUDIT_EVENT_HANDLERS_CONFIG = "/conf/audit-event-handlers.json";
54      /** Event handlers key. */
55      public static final String EVENT_HANDLERS = "eventHandlers";
56      /** Root path for audit endpoints. */
57      public static final String AUDIT_ROOT_PATH = "/audit";
58  
59      private AuditService auditService;
60  
61      @Override
62      public Handler start() throws HttpApplicationException {
63          final Router router = new Router();
64          final AuditServiceConfiguration auditServiceConfiguration = loadAuditServiceConfiguration();
65  
66          AuditServiceBuilder auditServiceBuilder = newAuditService();
67          auditServiceBuilder.withDependencyProvider(setupDependencies());
68          auditServiceBuilder.withConfiguration(auditServiceConfiguration);
69  
70          try (final InputStream eventHandlersConfig = this.getClass().getResourceAsStream(AUDIT_EVENT_HANDLERS_CONFIG)) {
71              JsonValue auditEventHandlers = getJson(eventHandlersConfig).get(EVENT_HANDLERS);
72              for (final JsonValue handlerConfig : auditEventHandlers) {
73                  try {
74                      registerHandlerToService(handlerConfig, auditServiceBuilder, this.getClass().getClassLoader());
75                  } catch (Exception ex) {
76                      logger.error("Unable to register handler defined by config: " + handlerConfig, ex);
77                  }
78              }
79          } catch (AuditException | IOException e) {
80              logger.error("Failed to read audit event handler configurations", e);
81              throw new HttpApplicationException(e);
82          }
83  
84          auditService = auditServiceBuilder.build();
85          try {
86              auditService.startup();
87          } catch (ServiceUnavailableException e) {
88              logger.error("Unable to start audit service", e);
89              throw new HttpApplicationException(e);
90          }
91          router.addRoute(requestUriMatcher(RoutingMode.STARTS_WITH, AUDIT_ROOT_PATH),
92                  CrestHttp.newHttpHandler(Resources.newInternalConnectionFactory(auditService)));
93          return router;
94      }
95  
96      @Override
97      public Factory<Buffer> getBufferFactory() {
98          return null;
99      }
100 
101     @Override
102     public void stop() {
103         if (auditService != null) {
104             auditService.shutdown();
105         }
106     }
107 
108     private DependencyProvider setupDependencies() throws HttpApplicationException {
109         DependencyProviderBase dependencyProvider = new DependencyProviderBase();
110         dependencyProvider.register(Client.class, new Client(new HttpClientHandler()));
111         dependencyProvider.register(BatchPublisherFactory.class, new BatchPublisherFactoryImpl());
112         return dependencyProvider;
113     }
114 
115     /** Loads the audit service configuration from JSON. */
116     private static AuditServiceConfiguration loadAuditServiceConfiguration() {
117         try (InputStream inputStream = getResourceAsStream("/conf/audit-service.json")) {
118             return AuditJsonConfig.parseAuditServiceConfiguration(inputStream);
119         } catch (AuditException | IOException e) {
120             final RuntimeException exception = new RuntimeException("Error while configuring the audit service", e);
121             logger.error(exception.getMessage(), e);
122             throw exception;
123         }
124     }
125 
126     private static InputStream getResourceAsStream(String path) {
127         return AuditHttpApplication.class.getResourceAsStream(path);
128     }
129 }