1   /*
2    *  GroupImpl.java
3    *
4    *  Copyright (c) 1998-2005, The University of Sheffield.
5    *
6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
7    *  software, licenced under the GNU Library General Public License,
8    *  Version 2, June 1991 (in the distribution as file licence.html,
9    *  and also available at http://gate.ac.uk/gate/licence.html).
10   *
11   *  Marin Dimitrov, 19/Sep/2001
12   *
13   *  $Id: GroupImpl.java,v 1.24 2005/01/11 13:51:36 ian Exp $
14   */
15  
16  package gate.security;
17  
18  import java.sql.*;
19  import java.util.List;
20  import java.util.Vector;
21  
22  import junit.framework.Assert;
23  
24  import gate.Gate;
25  import gate.event.*;
26  import gate.persist.DBHelper;
27  import gate.persist.PersistenceException;
28  import gate.util.MethodNotImplementedException;
29  
30  
31  public class GroupImpl
32    implements Group, ObjectModificationListener {
33  
34    /** --- */
35    private Long    id;
36  
37    /** --- */
38    private String  name;
39  
40    /** --- */
41    private List    users;
42  
43    /** --- */
44    private Connection conn;
45    /** --- */
46    private int dbType;
47  
48    /** --- */
49    private AccessControllerImpl ac;
50  
51    /** --- */
52    private Vector omModificationListeners;
53    /** --- */
54    private Vector omCreationListeners;
55    /** --- */
56    private Vector omDeletionListeners;
57  
58  
59  
60    public GroupImpl(Long id, String name, List users,AccessControllerImpl ac,Connection conn) {
61  
62      this.id = id;
63      this.name = name;
64      this.users = users;
65      this.ac = ac;
66      this.conn = conn;
67  
68      try {
69        String jdbcURL = conn.getMetaData().getURL();
70        this.dbType = DBHelper.getDatabaseType(jdbcURL);
71        Assert.assertTrue(this.dbType == DBHelper.ORACLE_DB ||
72                          this.dbType == DBHelper.POSTGRES_DB);
73      }
74      catch(SQLException sqex) {
75        sqex.printStackTrace();
76      }
77  
78      this.omModificationListeners = new Vector();
79      this.omCreationListeners = new Vector();
80      this.omDeletionListeners = new Vector();
81  
82      //register self as listener for the security factory events
83      //of type OBJECT_DELETED (users)
84      //don't forget that only AC can delete users, so he's the only
85      //source of such events
86      this.ac.registerObjectModificationListener(
87                                  this,
88                                  ObjectModificationEvent.OBJECT_DELETED);
89  
90    }
91  
92    /** --- */
93    public Long getID() {
94  
95      return id;
96    }
97  
98    /** --- */
99    public String getName() {
100 
101     return name;
102   }
103 
104   /** --- */
105   public List getUsers() {
106 
107     /** NOTE that we're returning a copy of the actuall collection of users
108      *  so that someone would not accidentaly modify it */
109     Vector copy = new Vector();
110     copy.addAll(this.users);
111     return copy;
112 
113   }
114 
115 
116   /** --- */
117   public void setName(String newName, Session s)
118     throws PersistenceException,SecurityException {
119 
120     //first check the session and then check whether the user is member of the group
121     if (this.ac.isValidSession(s) == false) {
122       throw new SecurityException("invalid session supplied");
123     }
124 
125     //2.1 check if the user is privileged
126     if (false == s.isPrivilegedSession() ) {
127       throw new SecurityException("insufficient privileges to change group name");
128     }
129 
130     CallableStatement stmt = null;
131     PreparedStatement pstmt = null;
132 
133     //Oracle / Postgres ?
134 
135     if (this.dbType == DBHelper.ORACLE_DB) {
136 
137       //1. update database
138       try {
139 
140         stmt = this.conn.prepareCall(
141                 "{ call "+Gate.DB_OWNER+".security.set_group_name(?,?)} ");
142         stmt.setLong(1,this.id.longValue());
143         stmt.setString(2,newName);
144         stmt.execute();
145         //release stmt???
146       }
147       catch(SQLException sqle) {
148         throw new PersistenceException("can't change group name in DB: ["+ sqle.getMessage()+"]");
149       }
150       finally {
151         DBHelper.cleanup(stmt);
152       }
153     }
154 
155     else if (this.dbType == DBHelper.POSTGRES_DB) {
156 
157       try {
158 
159         String sql = "select security_set_group_name(?,?) ";
160         pstmt = this.conn.prepareStatement(sql);
161         pstmt.setLong(1,this.id.longValue());
162         pstmt.setString(2,newName);
163         pstmt.execute();
164         //release stmt???
165       }
166       catch(SQLException sqle) {
167         throw new PersistenceException("can't change group name in DB: ["+ sqle.getMessage()+"]");
168       }
169       finally {
170         DBHelper.cleanup(pstmt);
171       }
172 
173     }
174 
175     else {
176       throw new IllegalArgumentException();
177     }
178 
179     //2. update memebr variable
180     this.name = newName;
181 
182     //3. create ObjectModificationEvent
183     ObjectModificationEvent e = new ObjectModificationEvent(
184                                           this,
185                                           ObjectModificationEvent.OBJECT_MODIFIED,
186                                           Group.OBJECT_CHANGE_NAME);
187 
188 
189     //4. fire ObjectModificationEvent for all who care
190     this.fireObjectModifiedEvent(e);
191 
192   }
193 
194 
195   /** --- */
196   public void addUser(Long userID, Session s)
197     throws PersistenceException,SecurityException{
198 
199     User usr = this.ac.findUser(userID);
200     addUser(usr,s);
201   }
202 
203   /** --- */
204   public void addUser(User usr, Session s)
205     throws PersistenceException,SecurityException{
206 
207     //1. check if the user is not already in group
208     if (this.users.contains(usr)) {
209       throw new SecurityException("User id=["+usr.getID()+"] is alredy member of group");
210     }
211 
212     //2. check the session
213     if (false == this.ac.isValidSession(s)) {
214       throw new SecurityException("invalid session provided");
215     }
216 
217     //2.1 check if the user is privileged
218     if (false == s.isPrivilegedSession() ) {
219       throw new SecurityException("insufficient privileges to add users");
220     }
221 
222     //3. update DB
223     CallableStatement stmt = null;
224     PreparedStatement pstmt = null;
225 
226     //Oracle / Postgres ?
227 
228     if (this.dbType == DBHelper.ORACLE_DB) {
229 
230       try {
231         stmt = this.conn.prepareCall(
232                   "{ call "+Gate.DB_OWNER+".security.add_user_to_group(?,?)} ");
233         stmt.setLong(1,this.id.longValue());
234         stmt.setLong(2,usr.getID().longValue());
235         stmt.execute();
236         //release stmt???
237       }
238       catch(SQLException sqle) {
239         throw new PersistenceException("can't add user to group in DB: ["+ sqle.getMessage()+"]");
240       }
241       finally {
242         DBHelper.cleanup(stmt);
243       }
244     }
245 
246     else if (this.dbType == DBHelper.POSTGRES_DB) {
247 
248       try {
249         String sql = "select security_add_user_to_group(?,?) ";
250         pstmt = this.conn.prepareStatement(sql);
251         pstmt.setLong(1,this.id.longValue());
252         pstmt.setLong(2,usr.getID().longValue());
253         pstmt.execute();
254         //release stmt???
255       }
256       catch(SQLException sqle) {
257         throw new PersistenceException("can't add user to group in DB: ["+ sqle.getMessage()+"]");
258       }
259       finally {
260         DBHelper.cleanup(pstmt);
261       }
262 
263     }
264 
265     else {
266       throw new IllegalArgumentException();
267     }
268 
269 
270     //4. create ObjectModificationEvent
271     ObjectModificationEvent e = new ObjectModificationEvent(
272                                           this,
273                                           ObjectModificationEvent.OBJECT_MODIFIED,
274                                           Group.OBJECT_CHANGE_ADDUSER);
275 
276     //5. update usr collection
277     this.users.add(usr);
278 
279     //6. notify user about the change
280     ((ObjectModificationListener)usr).objectModified(e);
281 
282     //7. fire ObjectModificationEvent for all other who care
283     fireObjectModifiedEvent(e);
284   }
285 
286 
287   /** --- */
288   public void removeUser(Long userID, Session s)
289     throws PersistenceException,SecurityException {
290 
291 
292     User usr = this.ac.findUser(userID);
293     removeUser(usr,s);
294   }
295 
296 
297   /** --- */
298   public void removeUser(User usr, Session s)
299     throws PersistenceException,SecurityException{
300 
301     //1. check if the user member of group
302     if (this.users.contains(usr) == false) {
303       throw new SecurityException("User id=["+usr.getID()+"] is NOT a member of group");
304     }
305 
306     //2. check the session
307     if (this.ac.isValidSession(s) == false) {
308       throw new SecurityException("invalid session provided");
309     }
310 
311     //2.1 check if the user is privileged
312     if (false == s.isPrivilegedSession() ) {
313       throw new SecurityException("insufficient privileges to remove users");
314     }
315 
316     //3. update DB
317     CallableStatement stmt = null;
318     PreparedStatement pstmt = null;
319 
320     //Oracle / Postgres ?
321 
322     if (this.dbType == DBHelper.ORACLE_DB) {
323       try {
324         stmt = this.conn.prepareCall(
325                   "{ call "+Gate.DB_OWNER+".security.remove_user_from_group(?,?)} ");
326         stmt.setLong(1,this.id.longValue());
327         stmt.setLong(2,usr.getID().longValue());
328         stmt.execute();
329         //release stmt???
330       }
331       catch(SQLException sqle) {
332         throw new PersistenceException("can't remove user from group in DB: ["+ sqle.getMessage()+"]");
333       }
334       finally {
335         DBHelper.cleanup(stmt);
336       }
337     }
338 
339     else if (this.dbType == DBHelper.POSTGRES_DB) {
340       try {
341         String sql = "select security_remove_user_from_group(?,?) ";
342         pstmt = this.conn.prepareStatement(sql);
343         pstmt.setLong(1,this.id.longValue());
344         pstmt.setLong(2,usr.getID().longValue());
345         pstmt.execute();
346         //release stmt???
347       }
348       catch(SQLException sqle) {
349         throw new PersistenceException("can't remove user from group in DB: ["+ sqle.getMessage()+"]");
350       }
351       finally {
352         DBHelper.cleanup(pstmt);
353       }
354     }
355 
356     else {
357       throw new IllegalArgumentException();
358     }
359 
360     //4. create ObjectModificationEvent
361     ObjectModificationEvent e = new ObjectModificationEvent(
362                                           this,
363                                           ObjectModificationEvent.OBJECT_MODIFIED,
364                                           Group.OBJECT_CHANGE_REMOVEUSER);
365 
366     //5. update usr collection
367     this.users.remove(usr);
368 
369     //6. notify user about the change
370     ((ObjectModificationListener)usr).objectModified(e);
371 
372     //7. fire ObjectModificationEvent for all other who care
373     fireObjectModifiedEvent(e);
374   }
375 
376 
377   //ObjectModificationListener interface
378   public void objectCreated(ObjectModificationEvent e) {
379 
380     //ignore, we don't care about creations
381     return;
382   }
383 
384   public void objectModified(ObjectModificationEvent e) {
385 
386     //ignore, we don't care about modifications
387     return;
388   }
389 
390   public void objectDeleted(ObjectModificationEvent e) {
391 
392     if (e.getSource() instanceof User) {
393 
394       User usr = (User)e.getSource();
395       //check if the user being deleted is one we contain
396       if (true == this.users.contains(usr)) {
397         this.users.remove(usr);
398       }
399 
400     }
401   }
402 
403   public void processGateEvent(GateEvent e){
404     throw new MethodNotImplementedException();
405   }
406 
407 
408   /**
409    *
410    *  this one is necessary for the contains() operations in Lists
411    *  It is possible that two users have two different GroupImpl that refer
412    *  to the very same GATE group in the DB, because they got it from the security
413    *  factory at different times. So we assume that two instances refer the same
414    *  GATE group if NAME1==NAME2
415    *
416    *  */
417   public boolean equals(Object obj)
418   {
419     Assert.assertTrue(obj instanceof Group);
420 
421     Group group2 = (Group)obj;
422 
423     return (this.id.equals(group2.getID()));
424   }
425 
426 
427   public void registerObjectModificationListener(ObjectModificationListener l,
428                                                  int eventType) {
429 
430     if (eventType != ObjectModificationEvent.OBJECT_CREATED &&
431         eventType != ObjectModificationEvent.OBJECT_DELETED &&
432         eventType != ObjectModificationEvent.OBJECT_MODIFIED) {
433 
434         throw new IllegalArgumentException();
435     }
436 
437     switch(eventType) {
438       case ObjectModificationEvent.OBJECT_CREATED :
439         //we never generate such events
440         Assert.fail();
441 //        this.omCreationListeners.add(l);
442         break;
443       case ObjectModificationEvent.OBJECT_DELETED :
444         //we never generate such events
445         Assert.fail();
446 //        this.omDeletionListeners.add(l);
447         break;
448       case ObjectModificationEvent.OBJECT_MODIFIED :
449         this.omModificationListeners.add(l);
450         break;
451       default:
452         Assert.fail();
453     }
454 
455   }
456 
457   private void fireObjectModifiedEvent(ObjectModificationEvent e) {
458 
459     //sanity check
460     if (e.getType() != ObjectModificationEvent.OBJECT_MODIFIED) {
461       throw new IllegalArgumentException();
462     }
463 
464     for (int i=0; i< this.omModificationListeners.size(); i++) {
465       ((ObjectModificationListener)omModificationListeners.elementAt(i)).objectModified(e);
466     }
467   }
468 
469   public void unregisterObjectModificationListener(ObjectModificationListener l,
470                                                    int eventType) {
471 
472     if (eventType != ObjectModificationEvent.OBJECT_CREATED &&
473         eventType != ObjectModificationEvent.OBJECT_DELETED &&
474         eventType != ObjectModificationEvent.OBJECT_MODIFIED) {
475 
476         throw new IllegalArgumentException();
477     }
478 
479     switch(eventType) {
480       case ObjectModificationEvent.OBJECT_CREATED :
481         this.omCreationListeners.remove(l);
482         break;
483       case ObjectModificationEvent.OBJECT_DELETED :
484         this.omDeletionListeners.remove(l);
485         break;
486       case ObjectModificationEvent.OBJECT_MODIFIED :
487         this.omModificationListeners.remove(l);
488         break;
489       default:
490         Assert.fail();
491     }
492   }
493 
494   /*package*/ void setUsers(Vector userIDs) {
495 
496     for (int i=0; i< userIDs.size(); i++) {
497       Long usr_id = (Long)userIDs.elementAt(i);
498       User usr = null;
499 
500       try {
501         usr = (User)this.ac.findUser(usr_id);
502       }
503       catch(SecurityException se) {
504         Assert.fail();
505       }
506       catch(PersistenceException se) {
507         Assert.fail();
508       }
509 
510       //is valid?
511       Assert.assertNotNull(usr);
512       Assert.assertTrue(usr instanceof User);
513       //add to our collection, which was empty so far
514       this.users.add(usr);
515     }
516 
517 
518   }
519 
520 }
521