// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.googlesource.gerrit.plugins.deleteproject;

import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.util.SystemLog;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;

@Singleton
class DeleteLog implements LifecycleListener {
  private static final String DELETE_LOG_NAME = "delete_log";
  private static final Logger log = LogManager.getLogger(DELETE_LOG_NAME);

  public static String ACCOUNT_ID = "accountId";
  public static String USER_NAME = "userName";
  public static String PROJECT_NAME = "projectName";
  public static String OPTIONS = "options";
  public static String ERROR = "error";

  private final SystemLog systemLog;
  private final ServerInformation serverInfo;
  private boolean started;

  @Inject
  public DeleteLog(SystemLog systemLog,
      ServerInformation serverInfo) {
    this.systemLog = systemLog;
    this.serverInfo = serverInfo;
  }

  public void onDelete(IdentifiedUser user, Project.NameKey project,
      DeleteProject.Input options, Exception ex) {
    LoggingEvent event = new LoggingEvent( //
        Logger.class.getName(), // fqnOfCategoryClass
        log, // logger
        TimeUtil.nowMs(), // when
        ex == null // level
            ? Level.INFO
            : Level.ERROR,
        ex == null // message text
            ? "OK"
            : "FAIL",
        Thread.currentThread().getName(), // thread name
        null, // exception information
        null, // current NDC string
        null, // caller location
        null // MDC properties
        );

    event.setProperty(ACCOUNT_ID, user.getAccountId().toString());
    event.setProperty(USER_NAME, user.getUserName());
    event.setProperty(PROJECT_NAME, project.get());

    if (options != null) {
      event.setProperty(OPTIONS,
          OutputFormat.JSON_COMPACT.newGson().toJson(options));
    }

    if (ex != null) {
      event.setProperty(ERROR, ex.toString());
    }

    log.callAppenders(event);
  }

  @Override
  public void start() {
    if (!started) {
      Logger deleteLogger = LogManager.getLogger(DELETE_LOG_NAME);
      deleteLogger.removeAllAppenders();
      deleteLogger.addAppender(systemLog.createAsyncAppender(
          deleteLogger.getName(), new DeleteLogLayout()));
      deleteLogger.setAdditivity(false);
      started = true;
    }
  }

  @Override
  public void stop() {
    // stop() is called when the plugin is unloaded or when the server is
    // shutdown. Only clean up when the server is shutting down to prevent
    // issues when the plugin is reloaded. Otherwise when Gerrit loads the new
    // plugin and then unloads the old one, the unload of the old plugin would
    // remove the appenders that were just created by the new plugin. This is
    // because the logger is static.
    if (serverInfo.getState() == ServerInformation.State.SHUTDOWN) {
      LogManager.getLogger(log.getName()).removeAllAppenders();
    }
  }
}

@@ -658,16 +658,194 @@
 oject;%0A%0A
+import com.google.common.collect.HashMultimap;%0Aimport com.google.common.collect.Multimap;%0Aimport com.google.gerrit.audit.AuditEvent;%0Aimport com.google.gerrit.audit.AuditService;%0A
 import c
@@ -878,16 +878,16 @@
 meUtil;%0A
-
 import c
@@ -1925,16 +1925,59 @@
 erInfo;%0A
+  private final AuditService auditService;%0A
   privat
@@ -2080,16 +2080,49 @@
 rverInfo
+,%0A      AuditService auditService
 ) %7B%0A    
@@ -2183,16 +2183,54 @@
 erInfo;%0A
+    this.auditService = auditService;%0A
   %7D%0A%0A  p
@@ -2342,24 +2342,56 @@
 ption ex) %7B%0A
+    long ts = TimeUtil.nowMs();%0A
     LoggingE
@@ -2509,32 +2509,18 @@
         
-TimeUtil.nowMs()
+ts
 , // whe
@@ -3262,24 +3262,24 @@
 ());%0A    %7D%0A%0A
-
     log.call
@@ -3295,16 +3295,828 @@
 (event);
+%0A%0A    audit(user, ts, project, options, ex);%0A  %7D%0A%0A  private void audit(IdentifiedUser user, long ts, Project.NameKey project,%0A      DeleteProject.Input options, Exception ex) %7B%0A    Multimap%3CString, Object%3E params = HashMultimap.create();%0A    params.put(%22class%22, DeleteLog.class);%0A    params.put(%22project%22, project.get());%0A    params.put(%22force%22, String.valueOf(options.force));%0A    params.put(%22preserve%22, String.valueOf(options.preserve));%0A%0A    auditService.dispatch(%0A        new AuditEvent(%0A            null, // sessionId%0A            user, // who%0A            ex == null // what%0A                ? %22ProjectDeletion%22%0A                : %22ProjectDeletionFailure%22,%0A            ts, // when%0A            params, // params%0A            ex != null // result%0A                ? ex.toString()%0A                : %22OK%22%0A        ));
 %0A  %7D%0A%0A  

Send audit event on project deletion