View Javadoc
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 }