1 /*
2 * The coLAB project
3 * Copyright (C) 2021-2023 AlbaSim, MEI, HEIG-VD, HES-SO
4 *
5 * Licensed under the MIT License
6 */
7 package ch.colabproject.colab.api.model.document;
8
9 import ch.colabproject.colab.api.exceptions.ColabMergeException;
10 import ch.colabproject.colab.api.model.ColabEntity;
11 import ch.colabproject.colab.api.model.tools.EntityHelper;
12 import java.util.ArrayList;
13 import java.util.List;
14 import javax.json.bind.annotation.JsonbTransient;
15 import javax.persistence.DiscriminatorValue;
16 import javax.persistence.Entity;
17 import javax.persistence.FetchType;
18 import javax.persistence.Index;
19 import javax.persistence.ManyToOne;
20 import javax.persistence.NamedQuery;
21 import javax.persistence.Table;
22 import javax.persistence.Transient;
23 import javax.validation.constraints.NotNull;
24
25 /**
26 * A reference to another existing abstract resource.
27 * <p>
28 * There can be a chain of references to aim at a resource.
29 * <p>
30 * Ref - [Ref -](0..*) Resource
31 * <p>
32 * The resource reference holds the comments for the resource in the context of a specific card /
33 * card type / card type reference / card content.
34 *
35 * @author sandra
36 */
37 @Entity
38 @Table(
39 indexes = {
40 @Index(columnList = "target_id"),
41 }
42 )
43 @DiscriminatorValue("RESOURCE_REF")
44 @NamedQuery(name = "ResourceRef.findDirectReferences",
45 query = "SELECT ref FROM ResourceRef ref "
46 + "WHERE ref.target IS NOT NULL AND ref.target.id = :targetId")
47 public class ResourceRef extends AbstractResource {
48
49 private static final long serialVersionUID = 1L;
50
51 // ---------------------------------------------------------------------------------------------
52 // fields
53 // ---------------------------------------------------------------------------------------------
54
55 /**
56 * Manually discard the resource = say that the target resource must not be displayed as an
57 * active resource at this reference level.
58 */
59 @NotNull
60 private boolean refused;
61
62 /**
63 * Automatically discard the resource = say that the target resource must not be displayed as an
64 * active resource at this reference level.
65 * <p>
66 * It can be because it is not published anymore or the reference is a rest of a former
67 * ancestor. The resource can be manually "revived".
68 * <p>
69 * The reference is not destroyed so that a rollback without loss of data is possible.
70 */
71 @NotNull
72 private boolean residual;
73
74 /**
75 * The abstract resource this reference aims at
76 */
77 @ManyToOne(fetch = FetchType.LAZY)
78 @NotNull
79 @JsonbTransient
80 private AbstractResource target;
81
82 /**
83 * The abstract resource id (serialization sugar)
84 */
85 @Transient
86 private Long targetId;
87
88 // ---------------------------------------------------------------------------------------------
89 // getters and setters
90 // ---------------------------------------------------------------------------------------------
91
92 /**
93 * @return if the targeted resource was manually marked as to be not displayed as active at this
94 * reference level
95 */
96 public boolean isRefused() {
97 return refused;
98 }
99
100 /**
101 * @param refused if the targeted resource was manually marked as to be not displayed as active
102 * at this reference level
103 */
104 public void setRefused(boolean refused) {
105 this.refused = refused;
106 }
107
108 /**
109 * @return if the targeted resource was automatically marked as to be not displayed as active at
110 * this reference level.
111 */
112 public boolean isResidual() {
113 return residual;
114 }
115
116 /**
117 * @param residual if the targeted resource was automatically marked as to be not displayed as
118 * active at this reference level.
119 */
120 public void setResidual(boolean residual) {
121 this.residual = residual;
122 }
123
124 /**
125 * @return the resource (or resource reference) this reference aims at
126 */
127 public AbstractResource getTarget() {
128 return target;
129 }
130
131 /**
132 * @param target the resource (or resource reference) this reference aims at
133 */
134 public void setTarget(AbstractResource target) {
135 this.target = target;
136 }
137
138 /**
139 * get the id of the resource (or resource reference) this reference aims at. To be sent to
140 * client
141 *
142 * @return id of the abstract resource or null
143 */
144 public Long getTargetId() {
145 if (target != null) {
146 return target.getId();
147 } else {
148 return targetId;
149 }
150 }
151
152 /**
153 * set the id of the resource (or resource reference) this reference aims at. For serialization
154 * only
155 *
156 * @param targetId the id of the resource or resource reference
157 */
158 public void setTargetId(Long targetId) {
159 this.targetId = targetId;
160 }
161
162 // ---------------------------------------------------------------------------------------------
163 // helpers
164 // ---------------------------------------------------------------------------------------------
165
166 @Override
167 public Resource resolve() {
168 if (this.target != null) {
169 return this.target.resolve();
170 }
171
172 return null;
173 }
174
175 @Override
176 public List<AbstractResource> expand() {
177 List<AbstractResource> list = new ArrayList<>();
178
179 list.add(this);
180 if (this.target != null) {
181 list.addAll(this.target.expand());
182 }
183 return list;
184 }
185
186 // ---------------------------------------------------------------------------------------------
187 // concerning the whole class
188 // ---------------------------------------------------------------------------------------------
189
190 @Override
191 public void mergeToUpdate(ColabEntity other) throws ColabMergeException {
192 super.mergeToUpdate(other);
193
194 // residual cannot be changed alone manually. It is handled by ResourceManager
195 // refused cannot be changed alone manually. It is handled by ResourceManager
196
197 if (!(other instanceof ResourceRef)) {
198 throw new ColabMergeException(this, other);
199 }
200 }
201
202 @Override
203 public void mergeToDuplicate(ColabEntity other) throws ColabMergeException {
204 super.mergeToDuplicate(other);
205
206 if (other instanceof ResourceRef) {
207 ResourceRef o = (ResourceRef) other;
208 this.setRefused(o.isRefused());
209 this.setResidual(o.isResidual());
210 } else {
211 throw new ColabMergeException(this, other);
212 }
213 }
214
215 @Override
216 public int hashCode() {
217 return EntityHelper.hashCode(this);
218 }
219
220 @Override
221 @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
222 public boolean equals(Object obj) {
223 return EntityHelper.equals(this, obj);
224 }
225
226 @Override
227 public String toString() {
228 return "ResourceRef{" + toPartialString() + ", refused=" + refused
229 + ", residual=" + residual + ", targetId=" + targetId + "}";
230 }
231
232 }