/*
* Permission.java
*
* Created on August 1, 2007, 10:03 AM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.atomojo.auth.service.db;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Iterator;
import java.util.UUID;
import org.infoset.xml.Element;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.XMLException;
import org.milowski.db.DB;
import org.milowski.db.DBCache;
import org.milowski.db.DBConnection;
import org.milowski.db.DBIterator;
import org.milowski.db.DBObject;
import org.milowski.db.DBQueryHandler;
import org.milowski.db.DBResultConstructor;
import org.milowski.db.DBUpdateHandler;
import org.milowski.db.Slot;
/**
*
* @author alex
*/
public class RealmUser extends DBObject<AuthDB> implements XMLObject
{
Realm realm;
String alias;
String name;
String email;
User user;
/** Creates a new instance of Permission */
public RealmUser(AuthDB db,int id,Realm realm,User user,String alias,String name,String email)
throws SQLException
{
super(db,id);
this.realm = realm;
this.alias = alias;
this.user = user;
this.name = name;
this.email = email;
}
public void delete()
throws SQLException
{
DBConnection connection = db.getConnection();
try {
db.LOG.info("Delete id "+id);
connection.deleteById(AuthDB.DELETE_REALM_USER_ALIAS, id);
connection.deleteById(AuthDB.DELETE_REALM_USER_GROUPS, id);
connection.deleteById(AuthDB.DELETE_REALM_USER, id);
db.realmUserCaches.get(realm).remove(id);
} finally {
db.release(connection);
}
}
public Realm getRealm() {
return realm;
}
public String getAlias()
{
return alias==null ? user.getAlias() : alias;
}
public boolean changeAlias(final String alias)
throws SQLException
{
if (alias!=null && this.alias!=null && alias.equals(this.alias)) {
// alias is the same so no change is needed
return true;
}
if (alias!=null && this.alias==null && alias.equals(user.getAlias())) {
// alias is the same as inherited so no change is needed
return true;
}
if (alias==null && user.getAlias()==null) {
// The user doesn't have an alias and this change requires an inherited alias
// so this can't be allowed
return false;
}
if (!db.isRealmUserAliasAvailable(realm,user,alias)) {
return false;
}
if (this.alias==null) {
// Only set the realm user's alias if the alias is not null
if (alias!=null) {
DBConnection connection = db.getConnection();
try {
connection.update(AuthDB.CREATE_REALM_USER_ALIAS, new DBUpdateHandler() {
public void prepare(PreparedStatement s)
throws SQLException
{
s.setInt(1,id);
s.setString(2,alias);
s.setString(3,id+"-"+alias);
}
});
} finally {
db.release(connection);
}
}
} else {
if (alias!=null) {
// just update
DBConnection connection = db.getConnection();
try {
connection.update(AuthDB.UPDATE_REALM_USER_ALIAS, new DBUpdateHandler() {
public void prepare(PreparedStatement s)
throws SQLException
{
s.setString(1,alias);
s.setString(2,id+"-"+alias);
s.setInt(3,id);
}
});
} finally {
db.release(connection);
}
} else {
// alias is null, delete so we inherit
DBConnection connection = db.getConnection();
try {
connection.deleteById(AuthDB.DELETE_REALM_USER_ALIAS, id);
} finally {
db.release(connection);
}
}
}
String prevAlias = getAlias();
if (prevAlias!=null) {
db.realmUserCaches.get(realm).removeByName(prevAlias);
}
this.alias = alias;
return true;
}
public boolean hasRole(final Role role)
throws SQLException
{
boolean result = user.hasRole(role);
if (!result) {
final Slot<Boolean> found = new Slot<Boolean>(Boolean.FALSE);
final DBCache<UUID,Group> cache = db.realmGroupCaches.get(realm);
DBConnection connection = db.getConnection();
try {
connection.query(AuthDB.GROUP_BY_REALM_USER, new DBQueryHandler() {
public void prepare(PreparedStatement s)
throws SQLException
{
s.setInt(1,realm.getId());
s.setInt(2,id);
}
public void onResults(ResultSet set)
throws SQLException
{
while (!found.get() && set.next()) {
Group group = cache.get(set.getInt(1));
found.set(group.hasRole(role));
}
}
});
} finally {
db.release(connection);
}
result = found.get();
}
return result;
}
public boolean hasPermission(Permission permission)
throws SQLException
{
boolean found = user.hasPermission(permission);
if (!found) {
Iterator<Group> groups = getGroups();
while (groups.hasNext()) {
if (groups.next().hasPermission(permission)) {
found = true;
}
}
}
return found;
}
public boolean isMemberOf(final Group group)
throws SQLException
{
return group.hasMember(this);
}
public void addGroup(Group group)
throws SQLException
{
if (!group.getRealm().equals(realm)) {
throw new IllegalArgumentException("The group realm "+group.getRealm().getUUID()+" is not the realm of the user realm "+realm.getUUID()+"");
}
if (!isMemberOf(group)) {
group.addMember(this);
}
}
public boolean removeGroup(Group group)
throws SQLException
{
return group.removeMember(this);
}
public Iterator<Group> getGroups()
throws SQLException
{
final Slot<Iterator<Group>> result = new Slot<Iterator<Group>>();
final DBCache<UUID,Group> cache = db.realmGroupCaches.get(realm);
final DBConnection connection = db.getConnection();
try {
connection.query(AuthDB.GROUP_BY_REALM_USER, new DBQueryHandler() {
public boolean shouldClose() {
return false;
}
public void prepare(PreparedStatement s)
throws SQLException
{
s.setInt(1,realm.getId());
s.setInt(2,id);
}
public void onResults(ResultSet set)
throws SQLException
{
result.set(new DBIterator<Group>(set,new DBResultConstructor<Group>() {
public Group newInstance(ResultSet set)
throws SQLException
{
return cache.get(set.getInt(1));
}
},db,connection));
}
});
} catch (SQLException ex) {
db.release(connection);
throw ex;
}
return result.get();
}
public String getName()
{
return name==null ? user.getName() : name;
}
public void setName(String name)
throws SQLException
{
if (name!=null && name.equals(user.getName())) {
name = null;
}
final String theName = name;
DBConnection connection = db.getConnection();
try {
connection.update(AuthDB.CHANGE_REALM_USER_NAME, new DBUpdateHandler() {
public void prepare(PreparedStatement s)
throws SQLException
{
if (theName==null) {
s.setNull(1,Types.VARCHAR);
} else {
s.setString(1,theName);
}
s.setInt(2,id);
}
});
} finally {
db.release(connection);
}
this.name = name;
}
public String getEmail()
{
return email==null ? user.getEmail() : email;
}
public void setEmail(String email)
throws SQLException
{
if (email!=null && email.equals(user.getEmail())) {
email = null;
}
final String theEmail = email;
DBConnection connection = db.getConnection();
try {
connection.update(AuthDB.CHANGE_REALM_USER_EMAIL, new DBUpdateHandler() {
public void prepare(PreparedStatement s)
throws SQLException
{
if (theEmail==null) {
s.setNull(1,Types.VARCHAR);
} else {
s.setString(1,theEmail);
}
s.setInt(2,id);
}
});
} finally {
db.release(connection);
}
this.email = email;
}
public User getUser()
{
return user;
}
public boolean equals(Object obj) {
if (!(obj instanceof RealmUser)) {
return false;
}
RealmUser other = (RealmUser)obj;
if (other.getUser().getUUID().equals(user.getUUID())) {
return alias==null ? other.getAlias()==null : alias.equals(other.getAlias());
} else {
return false;
}
}
public void generate(ItemConstructor constructor,ItemDestination dest)
throws XMLException
{
Element top = constructor.createElement(XML.USER_NAME);
top.setAttributeValue("id",user.getUUID().toString());
String avalue = getAlias();
// The alias shouldn't be null unless there is database corruption.
if (avalue!=null) {
top.setAttributeValue("alias",avalue);
}
dest.send(top);
if (getName()!=null) {
dest.send(constructor.createElement(XML.NAME_NAME));
dest.send(constructor.createCharacters(getName()));
dest.send(constructor.createElementEnd(XML.NAME_NAME));
}
if (getEmail()!=null) {
dest.send(constructor.createElement(XML.EMAIL_NAME));
dest.send(constructor.createCharacters(getEmail()));
dest.send(constructor.createElementEnd(XML.EMAIL_NAME));
}
dest.send(constructor.createElementEnd(XML.USER_NAME));
}
public void generate(ItemConstructor constructor,ItemDestination dest,boolean contents)
throws XMLException
{
generate(constructor,dest);
}
}