1    /*
2     * Copyright 2008 :torweg free software group
3     * 
4     * This program is free software: you can redistribute it and/or modify
5     * it under the terms of the GNU General Public License as published by
6     * the Free Software Foundation, either version 3 of the License, or
7     * (at your option) any later version.
8     * 
9     * This program is distributed in the hope that it will be useful,
10    * but WITHOUT ANY WARRANTY; without even the implied warranty of
11    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    * GNU General Public License for more details.
13    * 
14    * You should have received a copy of the GNU General Public License
15    * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16    *
17    */
18   package org.torweg.pulse.accesscontrol;
19   
20   import java.util.HashSet;
21   import java.util.List;
22   import java.util.Set;
23   
24   import javax.persistence.CascadeType;
25   import javax.persistence.Column;
26   import javax.persistence.Entity;
27   import javax.persistence.Lob;
28   import javax.persistence.ManyToMany;
29   import javax.persistence.Table;
30   import javax.persistence.UniqueConstraint;
31   import javax.xml.bind.annotation.XmlAccessOrder;
32   import javax.xml.bind.annotation.XmlAccessType;
33   import javax.xml.bind.annotation.XmlAccessorOrder;
34   import javax.xml.bind.annotation.XmlAccessorType;
35   import javax.xml.bind.annotation.XmlElement;
36   import javax.xml.bind.annotation.XmlElementWrapper;
37   import javax.xml.bind.annotation.XmlRootElement;
38   import javax.xml.bind.annotation.XmlTransient;
39   
40   import net.sf.json.JSONObject;
41   
42   import org.hibernate.LazyInitializationException;
43   import org.hibernate.Session;
44   import org.hibernate.criterion.Projections;
45   import org.jdom.Element;
46   import org.slf4j.Logger;
47   import org.slf4j.LoggerFactory;
48   import org.torweg.pulse.bundle.JDOMable;
49   import org.torweg.pulse.util.INameable;
50   
51   /**
52    * A {@code Role} is an entity used to combine {@code Group}s and {@code
53    * Permission}s, in order to reduce the number of {@code Group} s and {@code
54    * Permission}s, that have to be assigned to a certain {@code User}.
55    * 
56    * @author Christian Schatt, Daniel Dietz
57    * @version $Revision: 1479 $
58    */
59   @Entity
60   @Table(uniqueConstraints = { @UniqueConstraint(columnNames = "name") })
61   @XmlRootElement(name = "role")
62   @XmlAccessorOrder(XmlAccessOrder.UNDEFINED)
63   @XmlAccessorType(XmlAccessType.FIELD)
64   public class Role extends AbstractAccessControlObject implements INameable,
65           JDOMable {
66   
67       /**
68        * The serialVersionUID of the {@code Role}.
69        */
70       private static final long serialVersionUID = -421772203780732175L;
71   
72       /**
73        * the logger.
74        */
75       private static final Logger LOGGER = LoggerFactory.getLogger(Role.class);
76   
77       /**
78        * The description of the {@code Role}.
79        */
80       @Lob
81       @Column(length = 4096, nullable = false)
82       @XmlElement(name = "description")
83       private String description = "";
84   
85       /**
86        * The {@code Group}s associated with the {@code Role}.
87        */
88       @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE,
89               CascadeType.REFRESH })
90       @XmlTransient
91       // getter JAXB-annotated
92       private final Set<Group> groups = new HashSet<Group>();
93   
94       /**
95        * The {@code Permission}s associated with the {@code Role}.
96        */
97       @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE,
98               CascadeType.REFRESH })
99       @XmlTransient
100      // getter JAXB-annotated
101      private final Set<Permission> permissions = new HashSet<Permission>();
102  
103      /**
104       * The constructor used by Hibernate<sup>TM</sup>.
105       */
106      @Deprecated
107      protected Role() {
108          super();
109      }
110  
111      /**
112       * The constructor that sets the name of the {@code Role}.
113       * 
114       * @param nam
115       *            the name of the {@code Role}.
116       */
117      public Role(final String nam) {
118          super();
119          this.setName(nam);
120      }
121  
122      /**
123       * returns the description.
124       * 
125       * @return the description.
126       */
127      public final String getDescription() {
128          return this.description;
129      }
130  
131      /**
132       * sets the description.
133       * 
134       * @param d
135       *            the description to set
136       */
137      public final void setDescription(final String d) {
138          this.description = d;
139      }
140  
141      /**
142       * Returns a shallow copy of the {@code Role}'s {@code Collection} of
143       * {@code Group}s.
144       * 
145       * @return the {@code Group}s associated with the {@code Role}.
146       */
147      public final Set<Group> getGroups() {
148          return new HashSet<Group>(this.groups);
149      }
150  
151      /**
152       * For JAXB only.
153       * 
154       * @return this.getGroups()
155       */
156      @XmlElementWrapper(name = "groups")
157      @XmlElement(name = "group")
158      @SuppressWarnings("unused")
159      @Deprecated
160      private HashSet<Group> getGroupsJAXB() { // NOPMD
161          try {
162              return new HashSet<Group>(getGroups());
163          } catch (LazyInitializationException e) {
164              LOGGER.debug("ignored: {}", e.getLocalizedMessage());
165              return null;
166          }
167      }
168  
169      /**
170       * Adds a {@code Group} to the {@code Role}'s {@code Set} of {@code Group}s.
171       * 
172       * <p>
173       * If it already is part of the {@code Set}, it will not be added.
174       * </p>
175       * 
176       * @param group
177       *            the {@code Group} to be added.
178       * @return {@code true} if the {@code Set} changed as a result of the call.
179       */
180      public final boolean addGroup(final Group group) {
181          if (group == null) {
182              return false;
183          }
184          return this.groups.add(group);
185      }
186  
187      /**
188       * Removes a {@code Group} from the {@code Role}'s {@code Set} of {@code
189       * Group}s if it is part of it.
190       * 
191       * @param grp
192       *            the {@code Group} to be removed.
193       * @return {@code true} if the {@code Set} changed as a result of the call.
194       */
195      public final boolean removeGroup(final Group grp) {
196          if (grp == null) {
197              return false;
198          }
199          return this.groups.remove(grp);
200      }
201  
202      /**
203       * Returns a shallow copy of the {@code Role}'s {@code Collection} of
204       * {@code Permission}s.
205       * 
206       * @return the {@code Permission}s associated with the {@code Role}.
207       */
208      public final Set<Permission> getPermissions() {
209          return new HashSet<Permission>(this.permissions);
210      }
211  
212      /**
213       * For JAXB only.
214       * 
215       * @return this.getPermissions()
216       */
217      @XmlElementWrapper(name = "permissions")
218      @XmlElement(name = "permission")
219      @SuppressWarnings("unused")
220      @Deprecated
221      private HashSet<Permission> getPermissionsJAXB() { // NOPMD
222          try {
223              return new HashSet<Permission>(getPermissions());
224          } catch (LazyInitializationException e) {
225              LOGGER.debug("ignored: {}", e.getLocalizedMessage());
226              return null;
227          }
228      }
229  
230      /**
231       * Adds a {@code Permission} to the {@code Role}'s {@code Set} of {@code
232       * Permission}s.
233       * 
234       * <p>
235       * If it already is part of the {@code Set}, it will not be added.
236       * </p>
237       * 
238       * @param perm
239       *            the {@code Permission} to be added.
240       * @return {@code true} if the {@code Set} changed as a result of the call.
241       */
242      public final boolean addPermission(final Permission perm) {
243          if (perm == null) {
244              return false;
245          }
246          return this.permissions.add(perm);
247      }
248  
249      /**
250       * Removes a {@code Permission} from the {@code Role}'s {@code Set} of
251       * {@code Permission}s if it is part of it.
252       * 
253       * @param perm
254       *            the {@code Permission} to be removed.
255       * @return {@code true} if the {@code Set} changed as a result of the call.
256       */
257      public final boolean removePermission(final Permission perm) {
258          if (perm == null) {
259              return false;
260          }
261          return this.permissions.remove(perm);
262      }
263  
264      /**
265       * Returns the {@code User}s associated with the {@code Role} ordered by
266       * name.
267       * 
268       * @param s
269       *            the hibernate<sup>TM</sup>-{@code Session}
270       * 
271       * @return the {@code User}s associated with the {@code Role}.
272       */
273      @SuppressWarnings("unchecked")
274      public final List<User> getUsers(final Session s) {
275          return (List<User>) getAssociatedAbstractAccessControlObjects(s,
276                  User.class, "roles", getId());
277      }
278  
279      /**
280       * Returns the state of the {@code Role} as a JDOM {@code Element} .
281       * 
282       * @return the state of the {@code Role} as a JDOM {@code Element} .
283       */
284      public final Element deserializeToJDOM() {
285          Element element = new Element(Role.class.getSimpleName()).setAttribute(
286                  "class", Role.class.getCanonicalName());
287          if (this.getId() != null) {
288              element.setAttribute("id", this.getId().toString());
289          }
290          element.setAttribute("name", this.getName());
291          element
292                  .addContent(new Element("description")
293                          .setText(getDescription()));
294          try {
295              for (Group group : this.getGroups()) {
296                  element.addContent(group.deserializeToJDOM());
297              }
298          } catch (LazyInitializationException exception) {
299              element.removeChildren(Group.class.getSimpleName());
300          }
301          try {
302              for (Permission permission : this.getPermissions()) {
303                  element.addContent(permission.deserializeToJDOM());
304              }
305          } catch (LazyInitializationException exception) {
306              element.removeChildren(Permission.class.getSimpleName());
307          }
308          return element;
309      }
310  
311      /**
312       * Serializes the state of the {@code Role} as a {@code JSONObject}.
313       * 
314       * @return the state of the {@code Role} as a {@code JSONObject}
315       */
316      @Override
317      public final JSONObject toJSON() {
318          return toJSON(null);
319      }
320  
321      /**
322       * Returns the state of the {@code Role} as a {@code JSONObject}.
323       * <p>
324       * If a {@code Session} is given the number of {@code User}s, associated
325       * with the {@code Role} will be added to the JSON.
326       * </p>
327       * 
328       * @param s
329       *            the hibernate<sup>TM</sup>-{@code Session}
330       * 
331       * @return the state of the {@code Role} as a {@code JSONObject}.
332       */
333      public final JSONObject toJSON(final Session s) {
334  
335          JSONObject json = super.toJSON();
336  
337          json.put("name", getName());
338          json.put("description", getDescription());
339  
340          // adds info for ext-tree
341          json.put("uiProvider", "AccessControlTreeNodeUI");
342          json.put("leaf", true);
343          json.put("expandable", false);
344          json.put("allowChildren", false);
345          json.put("text", getName());
346  
347          // adds info for overview-grid
348          json.put("noGroups", getGroups().size());
349          json.put("noPermissions", getPermissions().size());
350          if (s != null) {
351              json.put("noUsers", (Long) getLoadCriteriaForClassWithAlias(s,
352                      User.class, "roles", getId()).setProjection(
353                      Projections.rowCount()).uniqueResult());
354          }
355          return json;
356      }
357  
358  }
359