/*
* RestoreDestination.java
*
* Created on August 4, 2007, 3:48 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.atomojo.auth.service.db;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.UUID;
import java.util.logging.Logger;
import org.infoset.xml.Element;
import org.infoset.xml.ElementEnd;
import org.infoset.xml.Item;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.Text;
import org.infoset.xml.XMLException;
import org.milowski.db.DB;
/**
*
* @author alex
*/
public class RestoreDestination implements ItemDestination
{
interface HandlerDestination extends ItemDestination {
int getStartLevel();
HandlerDestination pop();
}
class PermissionsDestination implements HandlerDestination {
HandlerDestination parent;
PermissionsDestination(HandlerDestination parent) {
this.parent = parent;
}
public int getStartLevel() {
return 2;
}
public HandlerDestination pop() {
return parent;
}
public void send(Item item)
throws XMLException
{
/*
if (level==2 && (item.getType()==Item.ItemType.ElementItem || item.getType()==Item.ItemType.ElementEndItem)) {
log.info(item.getType()==Item.ItemType.ElementItem ? "Starting locks:" : "Ending locks:");
try {
db.query("SELECT xid,type,mode,tablename FROM NEW org.apache.derby.diag.LockTable() AS LT",new DB.DBResultHandler() {
public void onResults(ResultSet set)
throws SQLException
{
while (set.next()) {
log.info("LOCK: "+set.getString(1)+","+set.getString(2)+","+set.getString(3)+","+set.getString(4));
}
}
});
} catch (SQLException ex) {
ex.printStackTrace();
}
}
*/
if (level==3) {
if (item.getType()==Item.ItemType.ElementItem) {
Element e = (Element)item;
if (e.getName().equals(XML.PERMISSION_NAME)) {
String sid = e.getAttributeValue("id");
String name = e.getAttributeValue("name");
if (sid==null) {
log.warning("A permission is missing the 'id' attribute.");
return;
}
if (name==null) {
log.warning("A permission is missing the 'name' attribute.");
return;
}
try {
UUID uuid = UUID.fromString(sid);
Permission p = db.getPermission(uuid);
if (p==null) {
log.info("Creating permission ("+name+","+sid+")");
p = db.createPermission(name,uuid);
} else {
if (!p.getName().equals(name)) {
log.warning("Permission ("+name+","+sid+") exists but has a different name, recreating.");
p.delete();
p = db.createPermission(name,uuid);
} else {
log.info("Permission ("+name+","+sid+") already exists.");
}
}
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on permission.");
} catch (SQLException ex) {
throw new XMLException("Database error creating permission "+sid,ex);
}
}
}
}
}
}
class RolesDestination implements HandlerDestination {
Role role;
HandlerDestination parent;
RolesDestination(HandlerDestination parent) {
this.parent = parent;
}
public int getStartLevel() {
return 2;
}
public HandlerDestination pop() {
return parent;
}
public void send(Item item)
throws XMLException
{
if (level==3) {
switch (item.getType()) {
case ElementItem:
Element e = (Element)item;
if (e.getName().equals(XML.ROLE_NAME)) {
String sid = e.getAttributeValue("id");
String name = e.getAttributeValue("name");
if (sid==null) {
log.warning("A role is missing the 'id' attribute.");
return;
}
if (name==null) {
log.warning("A role is missing the 'name' attribute.");
return;
}
try {
UUID uuid = UUID.fromString(sid);
role = db.getRole(uuid);
if (role==null) {
log.info("Creating role ("+name+","+sid+")");
role = db.createRole(name,uuid);
} else {
if (!role.getName().equals(name)) {
log.warning("Role ("+name+","+sid+") exists but has a different name, recreating.");
role.delete();
role = db.createRole(name,uuid);
} else {
log.info("Role ("+name+","+sid+") already exists.");
}
}
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on role.");
} catch (SQLException ex) {
throw new XMLException("Database error creating role "+sid,ex);
}
}
break;
case ElementEndItem:
role = null;
}
} else if (level==4 && role!=null) {
if (item.getType()==Item.ItemType.ElementItem) {
Element e = (Element)item;
if (e.getName().equals(XML.PERMISSION_NAME)) {
String sid = e.getAttributeValue("id");
String name = e.getAttributeValue("name");
if (sid==null && name==null) {
log.warning("A permission for role "+role.getUUID()+" must have at least the 'id' or 'name' attribute.");
return;
}
try {
Permission p = null;
if (sid!=null) {
UUID uuid = UUID.fromString(sid);
p = db.getPermission(uuid);
}
if (p==null && name!=null) {
p = db.getPermission(name);
}
if (p==null) {
log.warning("Cannot find permission ("+sid+","+name+") for role "+role.getUUID());
}
if (!role.hasPermission(p)) {
log.info("Adding permission ("+p.getName()+","+p.getUUID()+") to role.");
if (!role.addPermission(p)) {
log.warning("Cannot add permission "+p.getUUID()+" to role "+role.getUUID());
}
} else {
log.info("Role already has permission ("+p.getName()+","+p.getUUID()+") to role.");
}
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on permission.");
} catch (SQLException ex) {
throw new XMLException("Database error adding permission "+sid+" to role "+role.getUUID(),ex);
}
}
}
}
}
}
class UsersDestination implements HandlerDestination {
HandlerDestination parent;
String alias;
UUID id;
String name;
String email;
String passwordMd5;
StringBuilder buffer;
UsersDestination(HandlerDestination parent) {
this.parent = parent;
}
public int getStartLevel() {
return 2;
}
public HandlerDestination pop() {
return parent;
}
User create()
throws XMLException
{
User user = null;
if (id!=null) {
try {
user = db.getUser(id);
if (user!=null) {
log.info("Changing user ("+alias+","+id+","+name+","+email+")");
if (!user.changeAlias(alias)) {
log.warning("Could not change alias to '"+alias+"'");
}
user.setName(name);
/*
db.query("SELECT xid,type,mode,tablename FROM NEW org.apache.derby.diag.LockTable() AS LT",new DB.DBResultHandler() {
public void onResults(ResultSet set)
throws SQLException
{
while (set.next()) {
log.info("LOCK: "+set.getString(1)+","+set.getString(2)+","+set.getString(3)+","+set.getString(4));
}
}
});
*/
user.setEmail(email);
if (passwordMd5!=null) {
log.info("Setting password for "+id);
user.setEncryptedPassword("md5",passwordMd5);
}
} else {
log.info("Creating user ("+alias+","+id+","+name+","+email+")");
user = db.createUser(id,alias,name,email);
if (user==null) {
if (alias.equals("admin")) {
user = db.getUser("admin");
if (user!=null && user.hasPermission(db.getPermission(AuthDB.SUPERUSER_PERMISSION))) {
// we have a admin user to restore
user.delete();
user = db.createUser(id,alias,name,email);
if (user==null) {
log.severe("Cannot recreate admin user!");
}
} else {
log.warning("Creation of user with alias "+alias+" refused.");
}
} else {
log.warning("Creation of user with alias "+alias+" refused.");
}
}
if (user!=null && passwordMd5!=null) {
user.setEncryptedPassword("md5",passwordMd5);
}
}
id = null;
name = null;
email = null;
alias = null;
passwordMd5 = null;
} catch (SQLException ex) {
throw new XMLException("Database error while creating user "+id,ex);
} catch (NoSuchAlgorithmException ex) {
throw new XMLException("Password for user "+id+" could not be set.",ex);
}
}
return user;
}
public void send(Item item)
throws XMLException
{
if (level==3) {
switch (item.getType()) {
case ElementItem:
Element e = (Element)item;
if (e.getName().equals(XML.USER_NAME)) {
String sid = e.getAttributeValue("id");
alias = e.getAttributeValue("alias");
passwordMd5 = e.getAttributeValue("password-md5");
if (sid==null) {
log.warning("A user is missing the 'id' attribute.");
return;
}
try {
id = UUID.fromString(sid);
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on user.");
}
name = null;
email = null;
}
break;
case ElementEndItem:
create();
}
} else if (level==4) {
switch (item.getType()) {
case ElementItem:
{
Element e = (Element)item;
if (e.getName().equals(XML.NAME_NAME)) {
buffer = new StringBuilder();
} else if (e.getName().equals(XML.EMAIL_NAME)) {
buffer = new StringBuilder();
} else if (e.getName().equals(XML.ROLES_NAME)) {
User user = create();
if (user!=null) {
current = new UserRolesDestination(user,current);
current.send(item);
}
id = null;
}
}
break;
case ElementEndItem:
{
ElementEnd e = (ElementEnd)item;
if (e.getName().equals(XML.NAME_NAME)) {
name = buffer.toString();
} else if (e.getName().equals(XML.EMAIL_NAME)) {
email = buffer.toString();
}
buffer = null;
break;
}
case CharactersItem:
if (buffer!=null) {
buffer.append(((Text)item).getText());
}
}
} else if (item.getType()==Item.ItemType.CharactersItem && buffer!=null) {
buffer.append(((Text)item).getText());
}
}
}
class UserRolesDestination implements HandlerDestination {
HandlerDestination parent;
User user;
UserRolesDestination(User user,HandlerDestination parent) {
this.parent = parent;
this.user = user;
}
public int getStartLevel() {
return 4;
}
public HandlerDestination pop() {
return parent;
}
public void send(Item item)
throws XMLException
{
if (level==5 && item.getType()==Item.ItemType.ElementItem) {
Element e = (Element)item;
if (e.getName().equals(XML.ROLE_NAME)) {
String sid = e.getAttributeValue("id");
if (sid==null) {
log.warning("A role in user ("+user.getAlias()+","+user.getUUID()+") is missing the 'id' attribute.");
return;
}
try {
UUID id = UUID.fromString(sid);
Role role = db.getRole(id);
if (role==null) {
log.warning("Cannot find role "+id+" for user ("+user.getAlias()+","+user.getUUID()+").");
} else {
log.info("Adding role ("+role.getName()+","+role.getUUID()+")");
user.addRole(role);
}
} catch (SQLException ex) {
throw new XMLException("Database error while adding role "+sid+" to group ("+user.getAlias()+","+user.getUUID()+").",ex);
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on role in group ("+user.getAlias()+","+user.getUUID()+").");
}
}
}
}
}
class RealmsDestination implements HandlerDestination {
Realm realm;
HandlerDestination parent;
RealmsDestination(HandlerDestination parent) {
this.parent = parent;
}
public int getStartLevel() {
return 2;
}
public HandlerDestination pop() {
return parent;
}
public void send(Item item)
throws XMLException
{
if (level==3) {
switch (item.getType()) {
case ElementItem:
Element e = (Element)item;
if (e.getName().equals(XML.REALM_NAME)) {
String sid = e.getAttributeValue("id");
String name = e.getAttributeValue("name");
if (sid==null) {
log.warning("A realm is missing the 'id' attribute.");
return;
}
if (name==null) {
log.warning("A realm is missing the 'realm' attribute.");
return;
}
try {
UUID id = UUID.fromString(sid);
realm = db.getRealm(id);
if (realm!=null && !realm.getName().equals(name)) {
log.warning("Realm ("+name+","+sid+" exists but has a different name, recreating.");
realm.delete();
realm = null;
} else if (realm!=null) {
log.info("Realm ("+name+","+sid+") already exists.");
}
if (realm==null) {
log.info("Creating realm ("+name+","+sid+").");
realm = db.createRealm(name,id);
}
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on realm.");
} catch (SQLException ex) {
throw new XMLException("Database error on realm "+sid,ex);
}
}
break;
case ElementEndItem:
realm = null;
}
} else if (level==4) {
switch (item.getType()) {
case ElementItem:
Element e = (Element)item;
if (e.getName().equals(XML.USERS_NAME)) {
current = new RealmUsersDestination(realm,current);
current.send(item);
} else if (e.getName().equals(XML.GROUPS_NAME)) {
current = new RealmGroupsDestination(realm,current);
current.send(item);
}
}
}
}
}
class RealmUsersDestination implements HandlerDestination {
HandlerDestination parent;
Realm realm;
String alias;
UUID id;
String name;
String email;
StringBuilder buffer;
RealmUsersDestination(Realm realm,HandlerDestination parent) {
this.realm = realm;
this.parent = parent;
}
public int getStartLevel() {
return 4;
}
public HandlerDestination pop() {
return parent;
}
public void send(Item item)
throws XMLException
{
if (level==5) {
switch (item.getType()) {
case ElementItem:
Element e = (Element)item;
if (e.getName().equals(XML.USER_NAME)) {
String sid = e.getAttributeValue("id");
alias = e.getAttributeValue("alias");
if (sid==null) {
log.warning("A realm user is missing the 'id' attribute.");
return;
}
try {
id = UUID.fromString(sid);
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on realm user.");
}
name = null;
email = null;
}
break;
case ElementEndItem:
if (id!=null) {
try {
User user = db.getUser(id);
if (user==null) {
log.warning("Cannot find user with id "+id);
return;
}
RealmUser ruser = db.getRealmUser(realm,id);
if (ruser!=null) {
log.info("Changing realm user ("+alias+","+id+","+name+","+email+")");
if (!ruser.changeAlias(alias)) {
log.warning("Could not change alias to '"+alias+"'");
}
ruser.setName(name);
ruser.setEmail(email);
} else {
log.info("Creating realm user ("+alias+","+id+","+name+","+email+")");
ruser = db.createRealmUser(realm,user,alias,name,email);
if (ruser==null) {
log.warning("Creation of realm user with alias "+alias+" refused.");
}
}
id = null;
name = null;
email = null;
alias = null;
} catch (SQLException ex) {
throw new XMLException("Database error while creating realm user ("+alias+","+id+")",ex);
}
}
}
} else if (level==6) {
switch (item.getType()) {
case ElementItem:
{
Element e = (Element)item;
if (e.getName().equals(XML.NAME_NAME)) {
buffer = new StringBuilder();
} else if (e.getName().equals(XML.EMAIL_NAME)) {
buffer = new StringBuilder();
}
}
break;
case ElementEndItem:
{
ElementEnd e = (ElementEnd)item;
if (e.getName().equals(XML.NAME_NAME)) {
name = buffer.toString();
} else if (e.getName().equals(XML.EMAIL_NAME)) {
email = buffer.toString();
}
buffer = null;
break;
}
case CharactersItem:
if (buffer!=null) {
buffer.append(((Text)item).getText());
}
}
} else if (item.getType()==Item.ItemType.CharactersItem && buffer!=null) {
buffer.append(((Text)item).getText());
}
}
}
class RealmGroupsDestination implements HandlerDestination {
HandlerDestination parent;
Realm realm;
Group group;
RealmGroupsDestination(Realm realm,HandlerDestination parent) {
this.realm = realm;
this.parent = parent;
this.group = null;
}
public int getStartLevel() {
return 4;
}
public HandlerDestination pop() {
return parent;
}
public void send(Item item)
throws XMLException
{
if (level==5) {
switch (item.getType()) {
case ElementItem:
Element e = (Element)item;
if (e.getName().equals(XML.GROUP_NAME)) {
String sid = e.getAttributeValue("id");
String alias = e.getAttributeValue("alias");
if (sid==null) {
log.warning("A group is missing the 'id' attribute.");
return;
}
if (alias==null) {
log.warning("A group is missing the 'alias' attribute.");
return;
}
try {
UUID id = UUID.fromString(sid);
group = db.getGroup(realm,id);
if (group==null) {
log.info("Creating group ("+alias+","+id+")");
group = db.createGroup(realm,id,alias);
} else {
log.info("Group ("+alias+","+id+") already exists.");
}
} catch (SQLException ex) {
throw new XMLException("Database error while creating group ("+alias+","+sid+")",ex);
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on group.");
}
}
break;
case ElementEndItem:
group = null;
}
} else if (level==6) {
switch (item.getType()) {
case ElementItem:
{
Element e = (Element)item;
if (e.getName().equals(XML.ROLES_NAME)) {
current = new GroupRolesDestination(group,current);
current.send(item);
} else if (e.getName().equals(XML.USERS_NAME)) {
current = new GroupUsersDestination(group,current);
current.send(item);
}
}
}
}
}
}
class GroupRolesDestination implements HandlerDestination {
HandlerDestination parent;
Group group;
GroupRolesDestination(Group group,HandlerDestination parent) {
this.parent = parent;
this.group = group;
}
public int getStartLevel() {
return 6;
}
public HandlerDestination pop() {
return parent;
}
public void send(Item item)
throws XMLException
{
if (level==7 && item.getType()==Item.ItemType.ElementItem) {
Element e = (Element)item;
if (e.getName().equals(XML.ROLE_NAME)) {
String sid = e.getAttributeValue("id");
if (sid==null) {
log.warning("A role in group ("+group.getAlias()+","+group.getUUID()+") is missing the 'id' attribute.");
return;
}
try {
UUID id = UUID.fromString(sid);
Role role = db.getRole(id);
if (role==null) {
log.warning("Cannot find role "+id+" for group ("+group.getAlias()+","+group.getUUID()+").");
} else {
log.info("Adding role ("+role.getName()+","+role.getUUID()+")");
group.addRole(role);
}
} catch (SQLException ex) {
throw new XMLException("Database error while adding role "+sid+" to group ("+group.getAlias()+","+group.getUUID()+").",ex);
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on role in group ("+group.getAlias()+","+group.getUUID()+").");
}
}
}
}
}
class GroupUsersDestination implements HandlerDestination {
HandlerDestination parent;
Group group;
GroupUsersDestination(Group group,HandlerDestination parent) {
this.parent = parent;
this.group = group;
}
public int getStartLevel() {
return 6;
}
public HandlerDestination pop() {
return parent;
}
public void send(Item item)
throws XMLException
{
if (level==7 && item.getType()==Item.ItemType.ElementItem) {
Element e = (Element)item;
if (e.getName().equals(XML.USER_NAME)) {
String sid = e.getAttributeValue("id");
if (sid==null) {
log.warning("A user in group ("+group.getAlias()+","+group.getUUID()+") is missing the 'id' attribute.");
return;
}
try {
UUID id = UUID.fromString(sid);
RealmUser user = db.getRealmUser(group.getRealm(),id);
if (user==null) {
log.warning("Cannot find user "+id+" for group ("+group.getAlias()+","+group.getUUID()+").");
} else {
log.info("Adding member ("+user.getAlias()+","+user.getUser().getUUID()+")");
group.addMember(user);
}
} catch (SQLException ex) {
throw new XMLException("Database error while adding user "+sid+" to group ("+group.getAlias()+","+group.getUUID()+").",ex);
} catch (IllegalArgumentException ex) {
log.warning("Bad UUID value '"+sid+"' on user in group ("+group.getAlias()+","+group.getUUID()+").");
}
}
}
}
}
int level;
HandlerDestination current;
AuthDB db;
Logger log;
/**
* Creates a new instance of RestoreDestination
*/
public RestoreDestination(Logger log,AuthDB db)
{
this.log = log;
this.db = db;
this.level = 0;
this.current = new HandlerDestination() {
int flushLevel = -1;
public int getStartLevel() {
return 0;
}
public HandlerDestination pop() {
return this;
}
public void send(Item item)
throws XMLException
{
if (level==1) {
} else if (level==2) {
if (item.getType()==Item.ItemType.ElementItem) {
Name name = ((Element)item).getName();
if (name.equals(XML.PERMISSIONS_NAME)) {
current = new PermissionsDestination(current);
current.send(item);
} else if (name.equals(XML.ROLES_NAME)) {
current = new RolesDestination(current);
current.send(item);
} else if (name.equals(XML.USERS_NAME)) {
current = new UsersDestination(current);
current.send(item);
} else if (name.equals(XML.REALMS_NAME)) {
current = new RealmsDestination(current);
current.send(item);
}
}
}
}
};
}
public void send(Item item)
throws XMLException
{
switch (item.getType()) {
case ElementItem:
level++;
break;
}
current.send(item);
switch (item.getType()) {
case ElementEndItem:
level--;
if (level<current.getStartLevel()) {
current = current.pop();
}
}
}
}