Skip to content

Commit

Permalink
added persisted web hooks log including REST API. close #2283
Browse files Browse the repository at this point in the history
  • Loading branch information
j-dimension committed Apr 26, 2024
1 parent f64b67a commit 2d5a69d
Show file tree
Hide file tree
Showing 27 changed files with 5,519 additions and 30 deletions.
1 change: 1 addition & 0 deletions j-lawyer-server-entities/src/conf/persistence.xml
Expand Up @@ -57,6 +57,7 @@
<class>com.jdimension.jlawyer.persistence.InstantMessageMention</class>
<class>com.jdimension.jlawyer.persistence.EpostQueueBean</class>
<class>com.jdimension.jlawyer.persistence.CaseAccountEntry</class>
<class>com.jdimension.jlawyer.persistence.IntegrationHookLog</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<!-- changed from update to validate to avoid deployment during an update installer run to create columns that will be added by a sql script later in the process -->
Expand Down

Large diffs are not rendered by default.

@@ -0,0 +1,20 @@
CREATE TABLE integration_hooks_log (
`hook_id` VARCHAR(50) BINARY NOT NULL,
`hook_type` VARCHAR(100) BINARY NOT NULL,
`date_request` datetime default NULL,
`payload_size` BIGINT DEFAULT 0,
`duration` BIGINT DEFAULT 0,
`status` INTEGER DEFAULT 0,
`url` VARCHAR(750) BINARY NOT NULL,
`auth_user` VARCHAR(100) BINARY DEFAULT NULL,
`failed` BIT(1) DEFAULT 0,
`fail_message` VARCHAR(2500) BINARY DEFAULT NULL,
`response` VARCHAR(4500) BINARY DEFAULT NULL,

CONSTRAINT `pk_integration_hooks_log` PRIMARY KEY (`hook_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

alter table integration_hooks_log add index `IDX_INTHOOKSLOG_DREQ` (date_request);

insert into server_settings(settingKey, settingValue) values('jlawyer.server.database.version','2.6.1.4') ON DUPLICATE KEY UPDATE settingValue = '2.6.1.4';
commit;
Expand Up @@ -682,6 +682,7 @@ You should also get your employer (if you work as a programmer) or school,
import org.jlawyer.io.rest.v7.CasesEndpointV7;
import org.jlawyer.io.rest.v7.ConfigurationEndpointV7;
import org.jlawyer.io.rest.v7.MessagingEndpointV7;
import org.jlawyer.io.rest.v7.WebHooksEndpointV7;

@ApplicationPath("/rest")
public class EndpointServiceLocator extends Application
Expand Down Expand Up @@ -709,6 +710,7 @@ public Set<Class<?>> getClasses()
s.add(CasesEndpointV7.class);
s.add(MessagingEndpointV7.class);
s.add(AdministrationEndpointV7.class);
s.add(WebHooksEndpointV7.class);
return s;
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Expand Up @@ -57,6 +57,7 @@
<class>com.jdimension.jlawyer.persistence.InstantMessageMention</class>
<class>com.jdimension.jlawyer.persistence.EpostQueueBean</class>
<class>com.jdimension.jlawyer.persistence.CaseAccountEntry</class>
<class>com.jdimension.jlawyer.persistence.IntegrationHookLog</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<!-- changed from update to validate to avoid deployment during an update installer run to create columns that will be added by a sql script later in the process -->
Expand Down
Expand Up @@ -700,6 +700,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("addressId", this.getAddressId());
json.toJson(writer);
}
Expand Down
Expand Up @@ -700,6 +700,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("addressId", this.getAddressId());
json.toJson(writer);
}
Expand Down
Expand Up @@ -702,6 +702,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("addressId", this.getAddressId());
json.put("tagName", this.getTagName());
json.put("active", this.isActive());
Expand Down
Expand Up @@ -700,6 +700,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("addressId", this.getAddressId());
json.toJson(writer);
}
Expand Down
Expand Up @@ -700,6 +700,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("caseId", this.caseId);
json.toJson(writer);
}
Expand Down
Expand Up @@ -701,6 +701,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("caseId", this.caseId);
json.put("formId", this.formId);
json.toJson(writer);
Expand Down
Expand Up @@ -700,6 +700,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("caseId", this.caseId);
json.toJson(writer);
}
Expand Down
Expand Up @@ -702,6 +702,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("caseId", this.caseId);
json.put("tagName", this.getTagName());
json.put("active", this.isActive());
Expand Down
Expand Up @@ -700,6 +700,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("caseId", this.caseId);
json.toJson(writer);
}
Expand Down
Expand Up @@ -663,6 +663,7 @@ You should also get your employer (if you work as a programmer) or school,
*/
package com.jdimension.jlawyer.events;

import com.jdimension.jlawyer.persistence.utils.StringGenerator;
import java.io.Serializable;

/**
Expand All @@ -672,9 +673,11 @@ You should also get your employer (if you work as a programmer) or school,
public class CustomHook implements Serializable {

protected HookType hookType=null;
protected String hookId=null;

protected CustomHook(HookType hook) {
this.hookType=hook;
this.hookId=new StringGenerator().getID().toString();
}

public HookType getHookType() {
Expand All @@ -687,4 +690,18 @@ public HookType getHookType() {
public void setHookType(HookType hookType) {
this.hookType = hookType;
}

/**
* @return the hookId
*/
public String getHookId() {
return hookId;
}

/**
* @param hookId the hookId to set
*/
public void setHookId(String hookId) {
this.hookId = hookId;
}
}
Expand Up @@ -665,18 +665,26 @@ You should also get your employer (if you work as a programmer) or school,

import com.jdimension.jlawyer.persistence.IntegrationHook;
import com.jdimension.jlawyer.persistence.IntegrationHookFacadeLocal;
import com.jdimension.jlawyer.persistence.IntegrationHookLog;
import com.jdimension.jlawyer.persistence.IntegrationHookLogFacadeLocal;
import com.jdimension.jlawyer.security.Crypto;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.ejb.EJB;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.enterprise.event.ObservesAsync;
import javax.ws.rs.core.Response;
import org.apache.log4j.Logger;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.JerseyClient;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.glassfish.jersey.client.JerseyWebTarget;
import org.jboss.ejb3.annotation.TransactionTimeout;
import org.json.simple.Jsoner;

/**
Expand All @@ -691,54 +699,117 @@ public class CustomHooksService implements CustomHooksServiceLocal {

@EJB
private IntegrationHookFacadeLocal hookFacade;


@EJB
private IntegrationHookLogFacadeLocal hookLogsFacade;

// cache: avoid going to the database for the hooks with each event
private List<IntegrationHook> allHooks=null;
private List<IntegrationHook> allHooks = null;
// cache: crypto is expensive
private HashMap<String,String> hookPwd=new HashMap<>();
private HashMap<String, String> hookPwd = new HashMap<>();

@Override
public void onEvent(@ObservesAsync CustomHook evt) {
if(allHooks==null)
if (allHooks == null) {
resetCache();

for(IntegrationHook hook: allHooks) {
if(hook.getHookType().equals(evt.getHookType().name())) {
try {
executeHook(hook, evt);
} catch (Exception ex) {
log.error("failed to execute hook " + hook.getName(), ex);
}
}

for (IntegrationHook hook : allHooks) {
if (hook.getHookType().equals(evt.getHookType().name())) {
executeHook(hook, evt);
}
}
}

@Schedule(dayOfWeek = "1-7", hour = "12", minute = "31", second = "0", persistent = false)
// testing: @Schedule(hour = "*", minute = "*/2", persistent = false)
@TransactionTimeout(value = 10, unit = TimeUnit.MINUTES)
public void cleanupLogs() {

log.info("cleaning up old web hook logs");

Date currentDate = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(currentDate);
calendar.add(Calendar.DAY_OF_MONTH, -7);
Date sevenDaysAgo = calendar.getTime();

List<IntegrationHookLog> logs=this.hookLogsFacade.findOlderThan(sevenDaysAgo);
long removed=0;
if(logs!=null) {
for(IntegrationHookLog l: logs) {
this.hookLogsFacade.remove(l);
removed++;
}
}
if(removed>0)
log.info("removed " + removed + " old web hook logs");

}

private void executeHook(IntegrationHook hook, CustomHook evt) throws Exception {
log.info("Received custom hook event " + evt.getHookType().name());
String evtJson = Jsoner.serialize(evt);
log.debug("about to post the following event to custom hook: " + evtJson);

JerseyClient client=(JerseyClient)JerseyClientBuilder.createClient();
int connectTimeout=(int)(1000 * hook.getConnectionTimeout());
int readTimeout=(int)(1000 * hook.getReadTimeout());
client.property(ClientProperties.CONNECT_TIMEOUT, connectTimeout);
client.property(ClientProperties.READ_TIMEOUT, readTimeout);
private void executeHook(IntegrationHook hook, CustomHook evt) {
IntegrationHookLog hookLog=new IntegrationHookLog();
hookLog.setAuthenticationUser(hook.getAuthenticationUser());
hookLog.setHookId(evt.getHookId());
hookLog.setHookType(hook.getHookType());
hookLog.setRequestDate(new Date());
hookLog.setUrl(hook.getUrl());
hookLog.setStatus(-1);
hookLog.setDuration(0);
hookLog.setPayloadSize(-1);
hookLog.setResponse(null);

if(hook.getAuthenticationUser()!=null && !"".equalsIgnoreCase(hook.getAuthenticationUser())) {
if(!this.hookPwd.containsKey(hook.getName()))
this.hookPwd.put(hook.getName(), Crypto.decrypt(hook.getAuthenticationPwd()));
client.register(new HookAuthenticator(hook.getAuthenticationUser(), this.hookPwd.get(hook.getName())));
long start=System.currentTimeMillis();
try {
log.info("Received custom hook event " + evt.getHookType().name());
String evtJson = Jsoner.serialize(evt);
hookLog.setPayloadSize(evtJson.getBytes().length);
log.debug("about to post the following event to custom hook: " + evtJson);

JerseyClient client = (JerseyClient) JerseyClientBuilder.createClient();
int connectTimeout = (int) (1000 * hook.getConnectionTimeout());
int readTimeout = (int) (1000 * hook.getReadTimeout());
client.property(ClientProperties.CONNECT_TIMEOUT, connectTimeout);
client.property(ClientProperties.READ_TIMEOUT, readTimeout);

if (hook.getAuthenticationUser() != null && !"".equalsIgnoreCase(hook.getAuthenticationUser())) {
if (!this.hookPwd.containsKey(hook.getName())) {
this.hookPwd.put(hook.getName(), Crypto.decrypt(hook.getAuthenticationPwd()));
}
client.register(new HookAuthenticator(hook.getAuthenticationUser(), this.hookPwd.get(hook.getName())));
}

JerseyWebTarget webTarget = client.target(hook.getUrl());
Response response = webTarget.request(javax.ws.rs.core.MediaType.APPLICATION_JSON).post(javax.ws.rs.client.Entity.entity(evtJson, javax.ws.rs.core.MediaType.APPLICATION_JSON));

int statusCode = response.getStatus();
String returnValue = response.readEntity(String.class);

hookLog.setStatus(statusCode);
if(returnValue!=null) {
if(returnValue.length()>4500)
returnValue=returnValue.substring(0,4499);
}
hookLog.setResponse(returnValue);
hookLog.setDuration(System.currentTimeMillis()-start);
hookLog.setFailed(statusCode!=200);
hookLog.setFailureMessage(null);

} catch (Exception ex) {
log.error("failed to execute hook " + hook.getName(), ex);

hookLog.setStatus(1000);
hookLog.setDuration(System.currentTimeMillis()-start);
hookLog.setFailed(true);
hookLog.setFailureMessage(ex.getMessage());
}

JerseyWebTarget webTarget = client.target(hook.getUrl());
String returnValue = webTarget.request(javax.ws.rs.core.MediaType.APPLICATION_JSON).post(javax.ws.rs.client.Entity.entity(evtJson, javax.ws.rs.core.MediaType.APPLICATION_JSON), String.class);
log.debug("custom hook returned: " + returnValue);
this.hookLogsFacade.create(hookLog);
}

@Override
public void resetCache() {
this.allHooks=this.hookFacade.findAll();
this.allHooks = this.hookFacade.findAll();
this.hookPwd.clear();
}
}
Expand Up @@ -745,6 +745,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("documentId", this.documentId);
json.put("caseId", this.caseId);
json.put("documentName", this.documentName);
Expand Down
Expand Up @@ -745,6 +745,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("documentId", this.documentId);
json.put("caseId", this.caseId);
json.put("documentName", this.documentName);
Expand Down
Expand Up @@ -703,6 +703,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("caseId", this.caseId);
json.put("documentId", this.documentId);
json.put("tagName", this.getTagName());
Expand Down
Expand Up @@ -745,6 +745,7 @@ public String toJson() {
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("documentId", this.documentId);
json.put("caseId", this.caseId);
json.put("documentName", this.documentName);
Expand Down
Expand Up @@ -712,6 +712,7 @@ public void toJson(Writer writer) throws IOException {

final JsonObject json = new JsonObject();
json.put("hookType", this.hookType.name());
json.put("hookId", this.hookId);
json.put("messageId", this.getMessageId());
if(this.getSent()!=null)
json.put("sent", formatter.format(this.getSent()));
Expand Down

0 comments on commit 2d5a69d

Please sign in to comment.