Joaquín Reñé
2026-03-27 4ee50e257b32f6ec0f72907305d1f2b1212808a4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
* Copyright @ 2013 CurisTEC, S.A.S. All Rights Reserved.
*/
package net.curisit.securis.db;
import java.io.Serializable;
import java.util.Date;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import net.curisit.integrity.commons.Utils;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* BlockedRequest
* <p>
* Persistent record marking a request (by hash) as blocked.
* Primary key is the SHA-256 of the original request_data.
* Useful to avoid replay/duplicate processing.
*
* Mapping details:
* - Table: blocked_request
* - PK: hash (SHA-256(request_data))
* - Optional relation 'blockedBy' for auditing.
*
* @author JRA
* Last reviewed by JRA on Oct 7, 2025.
*/
@JsonAutoDetect
@JsonInclude(Include.NON_NULL)
@Entity
@Table(name = "blocked_request")
@JsonIgnoreProperties(ignoreUnknown = true)
public class BlockedRequest implements Serializable {
    private static final long serialVersionUID = 1L;
    /** Unique SHA-256 hash of {@link #requestData}. */
    @Id
    private String hash;
    /** Original request payload. */
    @Column(name = "request_data")
    @JsonProperty("request_data")
    private String requestData;
    /** Server-side creation timestamp. */
    @Column(name = "creation_timestamp")
    @JsonProperty("creation_timestamp")
    private Date creationTimestamp;
    /** User who blocked this request (optional, auditing). */
    @JsonIgnore
    @ManyToOne
    @JoinColumn(name = "blocked_by")
    private User blockedBy;
    // ---------------------------------------------------------------------
    // Getters & setters
    // ---------------------------------------------------------------------
    /**
    * getCreationTimestamp<p>
    * Get the creation timestamp.
    *
    * @return creationTimestamp
    */
    public Date getCreationTimestamp() { return creationTimestamp; }
    /**
    * setCreationTimestamp<p>
    * Set the creation timestamp.
    *
    * @param creationTimestamp
    */
    public void setCreationTimestamp(Date creationTimestamp) { this.creationTimestamp = creationTimestamp; }
    /**
    * equals<p>
    * Identity based on primary key (hash).
    */
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof BlockedRequest)) return false;
        BlockedRequest other = (BlockedRequest) obj;
        return (hash == null && other.hash == null) || (hash != null && hash.equals(other.hash));
    }
    /**
    * hashCode<p>
    * Hash based on primary key (hash).
    */
    @Override
    public int hashCode() { return (hash == null ? 0 : hash.hashCode()); }
    /**
    * getRequestData<p>
    * Get the original serialized request data.
    *
    * @return requestData
    */
    public String getRequestData() { return requestData; }
    /**
    * setRequestData<p>
    * Set the original request data and recompute the PK hash immediately.
    * Hash is computed as SHA-256 over the request string.
    *
    * @param requestData
    */
    public void setRequestData(String requestData) {
        this.requestData = requestData;
        this.hash = generateHash(this.requestData);
    }
    /**
    * getBlockedBy<p>
    * Return the user who blocked this request (if any).
    *
    * @return blockedBy
    */
    public User getBlockedBy() { return blockedBy; }
    /**
    * setBlockedBy<p>
    * Set the user who blocked this request.
    *
    * @param blockedBy
    */
    public void setBlockedBy(User blockedBy) { this.blockedBy = blockedBy; }
    // ---------------------------------------------------------------------
    // Static helpers
    // ---------------------------------------------------------------------
    /**
    * generateHash<p>
    * Compute the SHA-256 hex string for the given request data.
    *
    * @param reqData
    * @return sha256(reqData) or null if reqData is null
    */
    public static String generateHash(String reqData) {
        return (reqData != null ? Utils.sha256(reqData) : null);
    }
    /**
    * isRequestBlocked<p>
    * Check if a request payload is blocked by looking up its hash as the PK.
    *
    * @param requestData original payload
    * @param em JPA entity manager
    * @return true if an entry exists with the same hash
    */
    public static boolean isRequestBlocked(String requestData, EntityManager em) {
        String hash = generateHash(requestData);
        BlockedRequest br = em.find(BlockedRequest.class, hash);
        return br != null;
    }
}