HSAdmin Backend Domains, E-Mail, Datenbanken
Peter Hormanns
2011-03-22 6ca3aac6482885bbb5b44b5149829d90d82ab085
Paket-Modul
27 files added
1 files renamed
3 files deleted
21 files modified
1807 ■■■■■ changed files
hsarback/conf/META-INF/persistence.xml 6 ●●●●● patch | view | raw | blame | history
hsarback/lib/commons-beanutils-1.8.3.jar patch | view | raw | blame | history
hsarback/lib/commons-dbcp-1.4.jar patch | view | raw | blame | history
hsarback/lib/commons-lang-2.1.jar patch | view | raw | blame | history
hsarback/lib/commons-lang-2.4.jar patch | view | raw | blame | history
hsarback/lib/commons-logging-1.0.4.jar patch | view | raw | blame | history
hsarback/lib/commons-pool-1.5.4.jar patch | view | raw | blame | history
hsarback/lib/geronimo-jpa_2.0_spec-1.0.jar patch | view | raw | blame | history
hsarback/lib/geronimo-jpa_2.0_spec-1.1.jar patch | view | raw | blame | history
hsarback/lib/geronimo-validation_1.0_spec-1.1.jar patch | view | raw | blame | history
hsarback/lib/openjpa-2.0.0.jar patch | view | raw | blame | history
hsarback/lib/openjpa-2.1.0.jar patch | view | raw | blame | history
hsarback/lib/org.apache.bval.bundle-0.2-incubating.jar patch | view | raw | blame | history
hsarback/src/de/hsadmin/core/model/FieldValidation.java 12 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/core/model/GenericModuleImpl.java 70 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/cust/Customer.java 1 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/Database.java 222 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/DatabaseUser.java 200 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/JDBCProcessor.java 89 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlDatabase.java 46 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlDatabaseModuleImpl.java 42 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlDatabaseProcessorFactory.java 75 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlUser.java 43 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlUserModuleImpl.java 30 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlUserProcessorFactory.java 49 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlDatabase.java 50 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlDatabaseModuleImpl.java 41 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlDatabaseProcessorFactory.java 77 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlUser.java 42 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlUserModuleImpl.java 20 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlUserProcessorFactory.java 48 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/dom/Domain.java 18 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/email/EMailAddress.java 16 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/email/EMailAddressModuleImpl.java 10 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/email/EMailAlias.java 5 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/BaseComponent.java 24 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/BasePac.java 16 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/Component.java 34 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/ComponentId.java 39 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/INetAddress.java 2 ●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/Pac.java 56 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/PacComponent.java 49 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/PacComponentId.java 40 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/PacModuleImpl.java 83 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/user/UnixUser.java 6 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/remote/EMailAddressRemote.java 8 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/remote/PacRemote.java 75 ●●●●● patch | view | raw | blame | history
hsarback/src/org/apache/xmlrpc/webserver/XmlRpcServlet.properties 1 ●●●● patch | view | raw | blame | history
hsarback/test/de/hsadmin/remote/DomainTest.java 4 ●●●● patch | view | raw | blame | history
hsarback/test/de/hsadmin/remote/EMailAddressTest.java 12 ●●●●● patch | view | raw | blame | history
hsarback/test/de/hsadmin/remote/PacTest.java 144 ●●●●● patch | view | raw | blame | history
hsarback/test/de/hsadmin/remote/UnixUserTest.java 2 ●●● patch | view | raw | blame | history
hsarback/conf/META-INF/persistence.xml
@@ -19,6 +19,12 @@
        <class>de.hsadmin.mods.dom.Domain</class> 
        <class>de.hsadmin.mods.email.EMailAddress</class> 
        <class>de.hsadmin.mods.email.EMailAlias</class> 
        <!--
        <class>de.hsadmin.mods.db.MySqlUser</class>
        <class>de.hsadmin.mods.db.MySqlDatabase</class>
        <class>de.hsadmin.mods.db.PgSqlUser</class>
        <class>de.hsadmin.mods.db.PgSqlDatabase</class>
             -->
        <properties>
            <property name="openjpa.ConnectionDriverName" value="org.postgresql.Driver"/>
            <!-- 
hsarback/lib/commons-beanutils-1.8.3.jar
Binary files differ
hsarback/lib/commons-dbcp-1.4.jar
Binary files differ
hsarback/lib/commons-lang-2.1.jar
Binary files differ
hsarback/lib/commons-lang-2.4.jar
Binary files differ
hsarback/lib/commons-logging-1.0.4.jar
Binary files differ
hsarback/lib/commons-pool-1.5.4.jar
Binary files differ
hsarback/lib/geronimo-jpa_2.0_spec-1.0.jar
Binary files differ
hsarback/lib/geronimo-jpa_2.0_spec-1.1.jar
Binary files differ
hsarback/lib/geronimo-validation_1.0_spec-1.1.jar
Binary files differ
hsarback/lib/openjpa-2.0.0.jar
Binary files differ
hsarback/lib/openjpa-2.1.0.jar
Binary files differ
hsarback/lib/org.apache.bval.bundle-0.2-incubating.jar
Binary files differ
hsarback/src/de/hsadmin/core/model/FieldValidation.java
New file
@@ -0,0 +1,12 @@
package de.hsadmin.core.model;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldValidation {
    String value();
}
hsarback/src/de/hsadmin/core/model/GenericModuleImpl.java
@@ -1,6 +1,10 @@
package de.hsadmin.core.model;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -29,6 +33,7 @@
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        validateFields(newEntity);
        if (!newEntity.isNew())
            throw new HSAdminException("cannot add an already persistent entity");
        log.trace("add(" + newEntity + ")");
@@ -60,6 +65,7 @@
    @Override
    public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
        validateFields(existingEntity);
        if (existingEntity.isNew())
            return add(existingEntity);
        log.debug("update(" + existingEntity + ")");
@@ -75,4 +81,68 @@
        wrapper.delete(existingEntity);
    }
    private void validateFields(AbstractEntity anEntity) throws HSAdminException {
        Class<? extends AbstractEntity> clasz = anEntity.getClass();
        Field[] fields = clasz.getDeclaredFields();
        for (Field f : fields) {
            FieldValidation fieldValidation = f.getAnnotation(FieldValidation.class);
            if (fieldValidation != null) {
                try {
                    Method method = clasz.getMethod(getterName(f));
                    Object valueObject = method.invoke(anEntity);
                    if (valueObject instanceof String) {
                        if (!Pattern.matches(fieldValidation.value(), (String) valueObject)) {
                            throw new HSAdminException("validation of field " + f.getName() + " failed");
                        }
                    }
                } catch (SecurityException e) {
                    throw new HSAdminException(e);
                } catch (NoSuchMethodException e) {
                    throw new HSAdminException(e);
                } catch (IllegalArgumentException e) {
                    throw new HSAdminException(e);
                } catch (IllegalAccessException e) {
                    throw new HSAdminException(e);
                } catch (InvocationTargetException e) {
                    throw new HSAdminException(e);
                }
            }
        }
        // Bei Datenbanken und DB-Usern stehen die Attribute in der Oberklasse
        Class<?> superclass = clasz.getSuperclass();
        if (superclass != AbstractEntity.class) {
            fields = superclass.getDeclaredFields();
            for (Field f : fields) {
                FieldValidation fieldValidation = f.getAnnotation(FieldValidation.class);
                if (fieldValidation != null) {
                    try {
                        Method method = superclass.getMethod(getterName(f));
                        Object valueObject = method.invoke(anEntity);
                        if (valueObject instanceof String) {
                            if (!Pattern.matches(fieldValidation.value(), (String) valueObject)) {
                                throw new HSAdminException("validation of field " + f.getName() + " failed");
                            }
                        }
                    } catch (SecurityException e) {
                        throw new HSAdminException(e);
                    } catch (NoSuchMethodException e) {
                        throw new HSAdminException(e);
                    } catch (IllegalArgumentException e) {
                        throw new HSAdminException(e);
                    } catch (IllegalAccessException e) {
                        throw new HSAdminException(e);
                    } catch (InvocationTargetException e) {
                        throw new HSAdminException(e);
                    }
                }
            }
        }
    }
    private String getterName(Field f) {
        String name = f.getName();
        char firstChar = Character.toUpperCase(name.charAt(0));
        return "get" + firstChar + name.substring(1);
    }
}
hsarback/src/de/hsadmin/mods/cust/Customer.java
@@ -210,7 +210,6 @@
    // virtual attribute contractualContact
    // TODO: currently only a single contact can be managed
    @javax.persistence.Transient
    public Contact getContractualContact() {
        return getContacts().iterator().next();
    }
hsarback/src/de/hsadmin/mods/db/Database.java
New file
@@ -0,0 +1,222 @@
package de.hsadmin.mods.db;
import static javax.persistence.FetchType.EAGER;
import static javax.persistence.GenerationType.SEQUENCE;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
@MappedSuperclass
@SearchFilter("pac = :loginUserPac OR pac.customer.memberCode = :loginUserName")
public abstract class Database extends AbstractEntity implements Serializable {
    private static final long serialVersionUID = 6243815106074846080L;
    @Id
    @GeneratedValue(strategy = SEQUENCE, generator = "DatabaseSeqGen")
    @Column(name = "database_id", columnDefinition = "integer", updatable=false, insertable=false)
    private long id;
    @FieldValidation("[a-zA-Z]*")
    @Column(name = "engine", columnDefinition = "character varying(12)", updatable=false)
    private String instance;
    @FieldValidation("[a-z0-9\\_]*")
    @Column(name = "name", columnDefinition = "character varying(24)", updatable=false)
    private String name;
    @FieldValidation("[a-z0-9\\_]*")
    @Column(name = "owner", columnDefinition = "character varying(24)")
    private String owner;
    @JoinColumn(name = "packet_id", columnDefinition = "integer", updatable=false)
    @ManyToOne(fetch = EAGER)
    private Pac pac;
    @FieldValidation("[A-Za-z0-9\\_\\-]*")
    @Column(name = "encoding", columnDefinition = "character varying(24)", updatable=false)
    private String encoding;
    protected Database() {
        encoding = "UTF-8";
    }
    protected Database(String instance, Pac pac, String name, String owner,
            String encoding) {
        this.instance = instance;
        this.pac = pac;
        this.name = name;
        this.owner = owner;
        this.encoding = encoding;
    }
    @Override
    public void initialize(EntityManager em, UnixUser loginUser) {
        pac = loginUser.getPac(); // a default useful for the pac admin
    }
    public void complete(EntityManager em, UnixUser loginUser) {
        if (pac == null && name != null && name.length() > 0) {
            if (name.length() < 7 || name.charAt(5) != '_') {
                throw new SecurityException("database name '" + name
                        + "' not allowed");
            }
            // TODO: it's ugly having this code here, needs refactoring
            String pacName = name.substring(0, 5);
            try {
                // get the entities name (query part from FROM to WHERE)
                javax.persistence.Entity entityAnnot = Pac.class.getAnnotation(Entity.class);
                String queryString = "FROM " + entityAnnot.name() + " WHERE "
                        + Pac.createQueryFromStringKey(pacName);
                // set parameters
                Query query = em.createQuery(queryString);
                AbstractModuleImpl.setQueryParameter(query,
                        queryString, "loginUser", loginUser);
                AbstractModuleImpl.setQueryParameter(query,
                        queryString, "loginUserName", loginUser.getName());
                AbstractModuleImpl.setQueryParameter(query,
                        queryString, "loginUserPac", loginUser.getPac());
                pac = (Pac) query.getSingleResult();
            } catch (NoResultException exc) {
                throw new SecurityException("packet '" + pacName
                        + "' not found or access denied");
            }
        }
    }
    public static String createQueryFromStringKey(String humanKey) {
        return "name='" + humanKey + "'";
    }
    @Override
    public String createStringKey() {
        return getName();
    }
    @Override
    public boolean isNew() {
        return id == 0;
    }
    /**
     * returns the encoding in the style of the specific database
     */
    public abstract String getSystemEncoding();
    @Override
    public String getHiveName() {
        if (isNew())
            return null;
        else
            return getPac().getHiveName();
    }
    @Override
    public UnixUser owningUser(EntityManager em) {
        return getPac().owningUser(em);
    }
    /**
     * determines whether the given user has full read access on all merged fields of this entity
     */
    @Override
    public boolean isReadAllowedFor(UnixUser loginUser) {
        return loginUser.hasPacAdminRoleFor(getPac());
    }
    /**
     * determines whether the given user has full write access on all merged fields of this entity
     */
    @Override
    public boolean isWriteAllowedFor(UnixUser loginUser) {
        String pacName = pac.getName();
        if (!name.equals(pacName) && !name.startsWith(pacName + "_"))
            return false;
        return loginUser.hasPacAdminRoleFor(pac);
    }
    public abstract Class<? extends DatabaseUser> getSqlUserClass();
    @Override
    public long id() {
        return id;
    }
    public long getId() {
        return id;
    }
    protected void setId(long id) {
        this.id = id;
    }
    public String getInstance() {
        return instance;
    }
    public void setInstance(String instance) {
        this.instance = instance;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getOwner() {
        return owner;
    }
    public void setOwner(String owner) {
        this.owner = owner;
    }
    public Pac getPac() {
        return pac;
    }
    public void setPac(Pac pac) {
        this.pac = pac;
    }
    public String getEncoding() {
        return encoding;
    }
    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }
    /**
     * query restriction for access control
     */
    public static String restriction() {
        return
            // all databases of all pacs of customer
            "pac.customer.memberCode=:loginUserName OR " +
            // all aliases of packet admin
            "pac.name=:loginUserName";
    }
}
hsarback/src/de/hsadmin/mods/db/DatabaseUser.java
New file
@@ -0,0 +1,200 @@
package de.hsadmin.mods.db;
import static javax.persistence.FetchType.EAGER;
import static javax.persistence.GenerationType.SEQUENCE;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.Transient;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
@MappedSuperclass
public abstract class DatabaseUser extends AbstractEntity implements Serializable {
    private static final long serialVersionUID = -4840133372566213014L;
    @Id
    @GeneratedValue(strategy = SEQUENCE, generator = "DatabaseUserSeqGen")
    @Column(name = "dbuser_id", columnDefinition = "integer", updatable=false, insertable=false)
    private long id;
    @FieldValidation("[a-z0-9\\_]*")
    @Column(name = "name", columnDefinition = "character varying(24)", updatable=false)
    private String name;
    @FieldValidation("[^']*")
    @Transient
    private String password;
    @FieldValidation("[a-zA-Z]*")
    @Column(name = "engine", columnDefinition = "character varying(12)", updatable=false)
    protected String instance;
    @JoinColumn(name = "packet_id", columnDefinition = "integer", updatable=false)
    @ManyToOne(fetch = EAGER)
    protected Pac pac;
    protected DatabaseUser() {
    }
    protected DatabaseUser(String instance, Pac pac, String name,
            String password) {
        this.instance = instance;
        this.pac = pac;
        this.name = name;
        this.password = password;
    }
    @Override
    public void initialize(EntityManager em, UnixUser loginUser) {
        pac = loginUser.getPac(); // a default useful for the pac admin
    }
    public void complete(EntityManager em, UnixUser loginUser) {
        if (pac == null && name != null && name.length() > 0) {
            // TODO: it's ugly having this code here, needs refactoring
            String pacName = name.substring(0, 5);
            try {
                // get the entities name (query part from FROM to WHERE)
                javax.persistence.Entity entityAnnot = Pac.class
                        .getAnnotation(javax.persistence.Entity.class);
                String queryString = "FROM " + entityAnnot.name() + " WHERE "
                        + Pac.createQueryFromStringKey(pacName);
                // set parameters
                Query query = em.createQuery(queryString);
                AbstractModuleImpl.setQueryParameter(query, queryString,
                        "loginUser", loginUser);
                AbstractModuleImpl.setQueryParameter(query, queryString,
                        "loginUserName", loginUser.getName());
                AbstractModuleImpl.setQueryParameter(query, queryString,
                        "loginUserPac", loginUser.getPac());
                pac = (Pac) query.getSingleResult();
            } catch (NoResultException exc) {
                throw new SecurityException("packet '" + pacName
                        + "' not found or access denied");
            }
        }
    }
    @Override
    public String createStringKey() {
        return getName();
    }
    @Override
    public long id() {
        return id;
    }
    public long getId() {
        return id;
    }
    protected void setId(long id) {
        this.id = id;
    }
    public String getInstance() {
        return instance;
    }
    public void setInstance(String instance) {
        this.instance = instance;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public Pac getPac() {
        return pac;
    }
    public void setPac(Pac pac) {
        this.pac = pac;
    }
    @Override
    public boolean isNew() {
        return id == 0;
    }
    @Override
    public DatabaseUser merge(EntityManager em, UnixUser loginUser) {
        DatabaseUser dbEntity = (DatabaseUser) super.merge(em, loginUser);
        dbEntity.setPassword(this.getPassword());
        return dbEntity;
    }
    @Override
    public String getHiveName() {
        if (isNew())
            return null;
        else
            return getPac().getHiveName();
    }
    @Override
    public UnixUser owningUser(EntityManager em) {
        return getPac().owningUser(em);
    }
    /**
     * determines whether the given user has full read access on all merged
     * fields of this entity
     */
    @Override
    public boolean isReadAllowedFor(UnixUser loginUser) {
        return loginUser.hasPacAdminRoleFor(getPac());
    }
    /**
     * determines whether the given user has full write access on all merged
     * fields of this entity
     */
    @Override
    public boolean isWriteAllowedFor(UnixUser loginUser) {
        String pacName = pac.getName();
        if (!name.equals(pacName) && !name.startsWith(pacName + "_"))
            return false;
        return loginUser.hasPacAdminRoleFor(getPac());
    }
    /**
     * query restriction for access control
     */
    public static String restriction() {
        return
            // all databases of all pacs of customer
            "pac.customer.memberCode=:loginUserName OR " +
            //     all aliases of packet admin
            "pac.name=:loginUserName";
    }
}
hsarback/src/de/hsadmin/mods/db/JDBCProcessor.java
New file
@@ -0,0 +1,89 @@
package de.hsadmin.mods.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import de.hsadmin.core.qserv.AbstractProcessor;
import de.hsadmin.core.qserv.ProcessorException;
import de.hsadmin.core.util.Config;
public class JDBCProcessor extends AbstractProcessor {
    private static final long serialVersionUID = 7702753017749022325L;
    private String driver;
    private String url;
    private String user;
    private String password;
    private List<String> sql;
    public JDBCProcessor(String driver, String url, String user, String password) {
        this.driver = driver;
        this.url = url;
        this.user = user;
        this.password = password;
    }
    public JDBCProcessor(String driver, String url) {
        this.driver = driver;
        this.url = url;
    }
    public void addSQL(String sqlStatement) {
        if (sql == null)
            sql = new ArrayList<String>();
        sql.add(sqlStatement);
    }
    public Object process() throws ProcessorException {
        Connection c = null;
        Config config = Config.getInstance();
        if ("com.mysql.jdbc.Driver".equals(driver)) {
            if (user == null)
                user = config.getProperty("mysqladmin.user", "root");
            if (password == null)
                password = config.getProperty("mysqladmin.password");
        }
        if ("org.postgresql.Driver".equals(driver)) {
            if (user == null)
                user = config.getProperty("pgsqladmin.user", "postgres");
            if (password == null)
                password = config.getProperty("pgsqladmin.password");
        }
        if (user == null || password == null) {
            throw new ProcessorException("database admin-user configuration failed");
        }
        try {
            Class.forName(driver);
            c = DriverManager.getConnection(url, user, password);
            if (c == null)
                throw new ProcessorException("cannot connect to '" + url + "'");
            Statement s = c.createStatement();
            for (String sqlStatement : sql) {
                s.addBatch(sqlStatement);
                System.out.println("SQL: " + sqlStatement);
            }
            return s.executeBatch();
        } catch (SQLException aSqlExc) {
            Exception exc = aSqlExc.getNextException();
            if (exc == null)
                exc = aSqlExc;
            System.out.println("ERR: " + exc.getMessage());
            throw new ProcessorException(aSqlExc.getMessage() + ", reason: "
                    + exc.getMessage());
        } catch (Exception aExc) {
            throw new ProcessorException(aExc.getMessage());
        } finally {
            if (c != null) {
                try {
                    c.close();
                } catch (Exception exc) {
                }
            }
        }
    }
}
hsarback/src/de/hsadmin/mods/db/MySqlDatabase.java
New file
@@ -0,0 +1,46 @@
package de.hsadmin.mods.db;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
@Entity(name = "MySqlDatabases")
@Table(name = "database")
@SequenceGenerator(name = "DatabaseSeqGen", sequenceName = "database_database_id_seq")
@EntityInfo(name = "MySQL Datenbank")
@SearchFilter("instance = 'mysql' AND (" + "    pac = :loginUserPac OR "
        + "    pac.customer.memberCode = :loginUserName )")
public class MySqlDatabase extends Database implements Serializable {
    private static final long serialVersionUID = 2862112440807946042L;
    public MySqlDatabase() {
        setInstance("mysql");
        setEncoding("UTF-8");
    }
    public MySqlDatabase(Pac pac, String name, String owner, String encoding) {
        super("mysql", pac, name, owner, encoding);
    }
    public String getSystemEncoding() {
        String sysEnc = getEncoding().toLowerCase().replaceAll("-", "");
        return sysEnc;
    }
    @Override
    public Class<? extends DatabaseUser> getSqlUserClass() {
        return MySqlUser.class;
    }
    public static String restriction() {
        return "instance='mysql' AND ( " + Database.restriction() + " )";
    }
}
hsarback/src/de/hsadmin/mods/db/MySqlDatabaseModuleImpl.java
New file
@@ -0,0 +1,42 @@
package de.hsadmin.mods.db;
import java.util.List;
import javax.persistence.EntityManager;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.AuthorisationException;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.mods.user.UnixUser;
public class MySqlDatabaseModuleImpl extends AbstractModuleImpl {
    @Override
    public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass,
            String condition, String orderBy) throws HSAdminException {
        if (orderBy == null || orderBy.length() == 0) {
            orderBy = "ORDER BY name ASC";
        }
        return super.search(entityClass, condition, orderBy);
    }
    @Override
    public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
        EntityManager em = getTransaction().getEntityManager();
        UnixUser unixUser = getLoginUser();
        MySqlDatabase detachtedDB = (MySqlDatabase) existingEntity;
        MySqlDatabase attachedDB = em.find(MySqlDatabase.class, detachtedDB.getId());
        if (!attachedDB.getName().equals(detachtedDB.getName())) {
            throw new AuthorisationException(unixUser, "update", existingEntity, "name");
        }
        if (!attachedDB.getEncoding().equals(detachtedDB.getEncoding())) {
            throw new AuthorisationException(unixUser, "update", existingEntity, "encoding");
        }
        if (!attachedDB.getInstance().equals(detachtedDB.getInstance())) {
            throw new AuthorisationException(unixUser, "update", existingEntity, "instance");
        }
        return super.update(existingEntity);
    }
}
hsarback/src/de/hsadmin/mods/db/MySqlDatabaseProcessorFactory.java
New file
@@ -0,0 +1,75 @@
package de.hsadmin.mods.db;
import javax.persistence.EntityManager;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.qserv.EntityProcessorFactory;
import de.hsadmin.core.qserv.Processor;
/** Factory class which creates Processor instances for dealing with UNIX user accounts.
 *
 * @author mi
 */
public class MySqlDatabaseProcessorFactory implements EntityProcessorFactory {
    /// creates a JDBCProcessor for MySQL and the given user
    public static JDBCProcessor createMySqlProcessor( String database, String user, String password )
    {
        return new JDBCProcessor( "com.mysql.jdbc.Driver",
                "jdbc:mysql://localhost/" + database,
                user, password );
    }
    /// creates a JDBCProcessor for the MySQL admin user
    public static JDBCProcessor createMySqlAdminProcessor()
    {
        return new JDBCProcessor( "com.mysql.jdbc.Driver", "jdbc:mysql://localhost/" );
    }
    /// @return a Processor which creates a new database
    public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity)
    {
        Database db = (Database) entity;
        assert db.getInstance().equals("mysql");
        JDBCProcessor aJDBCP = null;
        String aName = AbstractEntity.escapeString( db.getName() );
        String aOwner = AbstractEntity.escapeString( db.getOwner() );
        String aEncoding = AbstractEntity.escapeString( db.getSystemEncoding() );
        aJDBCP = createMySqlAdminProcessor();
        aJDBCP.addSQL( "CREATE DATABASE " + aName + " " +
                "DEFAULT CHARACTER SET '" + aEncoding + "'");
        aJDBCP.addSQL( "GRANT ALL ON " + aName + ".* TO '" + aOwner + "'@'%' WITH GRANT OPTION" );
        return aJDBCP;
    }
    /// @return a Processor which updates a preexisting database
    public <T extends AbstractEntity> Processor createUpdateProcessor(EntityManager em, T entity)
    {
        Database db = (Database) entity;
        assert db.getInstance().equals("mysql");
        String aName = AbstractEntity.escapeString( db.getName() );
        String aOwner = AbstractEntity.escapeString( db.getOwner() );
        String aEncoding = AbstractEntity.escapeString( db.getSystemEncoding() );
        JDBCProcessor aJDBCP = null;
        aJDBCP = createMySqlAdminProcessor();
        aJDBCP.addSQL( "ALTER DATABASE " + aName + " DEFAULT CHARACTER SET '" + aEncoding + "'" );
        aJDBCP.addSQL( "GRANT ALL ON " + aName + ".* TO '" + aOwner + "'@'%'" );
        // TODO: alte Admin-Rechte entziehen
        return aJDBCP;
    }
    /// @return a Processor which deletes an existing database
    public <T extends AbstractEntity> Processor createDeleteProcessor(EntityManager em, T entity)
    {
        Database db = (Database) entity;
        assert db.getInstance().equals("mysql");
        JDBCProcessor aJDBCP = createMySqlAdminProcessor();
        String aName = AbstractEntity.escapeString( db.getName() );
        String aOwner = AbstractEntity.escapeString( db.getOwner() );
        aJDBCP.addSQL( "REVOKE ALL ON " + aName + ".* FROM '" + aOwner + "'@'%'" );
        aJDBCP.addSQL( "DROP DATABASE " + aName );
        return aJDBCP;
    }
}
hsarback/src/de/hsadmin/mods/db/MySqlUser.java
New file
@@ -0,0 +1,43 @@
package de.hsadmin.mods.db;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
@Entity(name = "MySqlUsers")
@Table(name = "database_user")
@SequenceGenerator(name = "DatabaseUserSeqGen", sequenceName = "dbuser_dbuser_id_seq")
@EntityInfo(name = "MySQL Konto")
@SearchFilter("instance = 'mysql' AND ("
        + "    pac = :loginUserPac OR "
        + "    pac.customer.memberCode = :loginUserName )")
public class MySqlUser extends DatabaseUser implements Serializable {
    private static final long serialVersionUID = 6218494776881999478L;
    public static String createQueryFromStringKey(String humanKey) {
        return "name='" + humanKey + "' AND instance='mysql'";
    }
    public MySqlUser() {
        setInstance("mysql");
    }
    public MySqlUser(Pac pac, String name, String password) {
        super("mysql", pac, name, password);
    }
    /**
     *  query restriction for access control
     */
    public static String restriction() {
        return "instance='mysql' AND ( " + DatabaseUser.restriction() + " )";
    }
}
hsarback/src/de/hsadmin/mods/db/MySqlUserModuleImpl.java
New file
@@ -0,0 +1,30 @@
package de.hsadmin.mods.db;
import java.util.List;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.AuthorisationException;
import de.hsadmin.core.model.HSAdminException;
public class MySqlUserModuleImpl extends AbstractModuleImpl {
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        MySqlUser user = (MySqlUser) newEntity;
        if (user.getName().length() > 16) {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
        }
        return super.add(newEntity);
    }
    @Override
    public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass,
            String condition, String orderBy) throws HSAdminException {
        if (orderBy == null || orderBy.length() == 0) {
            orderBy = "ORDER BY name ASC";
        }
        return super.search(entityClass, condition, orderBy);
    }
}
hsarback/src/de/hsadmin/mods/db/MySqlUserProcessorFactory.java
New file
@@ -0,0 +1,49 @@
package de.hsadmin.mods.db;
import javax.persistence.EntityManager;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.qserv.EntityProcessorFactory;
import de.hsadmin.core.qserv.Processor;
/**
 * Factory class which creates Processor instances for dealing with UNIX user
 * accounts.
 *
 * @author mi
 */
public class MySqlUserProcessorFactory implements EntityProcessorFactory {
    public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity) {
        DatabaseUser dbu = (DatabaseUser) entity;
        assert dbu.getInstance().equals("mysql");
        JDBCProcessor aJDBCP = MySqlDatabaseProcessorFactory.createMySqlAdminProcessor();
        String aName = AbstractEntity.escapeString(dbu.getName());
        String aPassword = AbstractEntity.escapeString(dbu.getPassword());
        aJDBCP.addSQL("CREATE USER '" + aName + "'@'%'" + " IDENTIFIED BY '" + aPassword + "'");
        return aJDBCP;
    }
    public <T extends AbstractEntity> Processor createUpdateProcessor(
            EntityManager em, T entity) {
        DatabaseUser dbu = (DatabaseUser) entity;
        assert dbu.getInstance().equals("mysql");
        JDBCProcessor aJDBCP = MySqlDatabaseProcessorFactory.createMySqlAdminProcessor();
        String aName = AbstractEntity.escapeString(dbu.getName());
        String aPassword = AbstractEntity.escapeString(dbu.getPassword());
        aJDBCP.addSQL("SET PASSWORD FOR  '" + aName + "'@'%'" + " = PASSWORD('" + aPassword + "')");
        return aJDBCP;
    }
    public <T extends AbstractEntity> Processor createDeleteProcessor(
            EntityManager em, T entity) {
        DatabaseUser dbu = (DatabaseUser) entity;
        assert dbu.getInstance().equals("mysql");
        JDBCProcessor aJDBCP = MySqlDatabaseProcessorFactory.createMySqlAdminProcessor();
        String aName = AbstractEntity.escapeString(dbu.getName());
        aJDBCP.addSQL("REVOKE ALL PRIVILEGES, GRANT OPTION FROM '" + aName + "'@'%'");
        aJDBCP.addSQL("DROP USER '" + aName + "'@'%'");
        return aJDBCP;
    }
}
hsarback/src/de/hsadmin/mods/db/PgSqlDatabase.java
New file
@@ -0,0 +1,50 @@
package de.hsadmin.mods.db;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
@Entity(name = "PgSqlDatabases")
@Table(name = "database")
@SequenceGenerator(name = "DatabaseSeqGen", sequenceName = "database_database_id_seq")
@EntityInfo(name = "PostgreSQL Datenbank")
@SearchFilter("instance = 'pgsql' AND ("
        + "    pac = :loginUserPac OR "
        + "    pac.customer.memberCode = :loginUserName )")
public class PgSqlDatabase extends Database implements Serializable {
    private static final long serialVersionUID = 6688358817554938015L;
    public PgSqlDatabase() {
        setInstance("pgsql");
        setEncoding("UTF-8");
    }
    public PgSqlDatabase(Pac pac, String name, String owner, String encoding) {
        super("pgsql", pac, name, owner, encoding);
    }
    @Override
    public Class<? extends DatabaseUser> getSqlUserClass() {
        return PgSqlUser.class;
    }
    public String getSystemEncoding() {
        return getEncoding();
    }
    /**
     *  query restriction for access control
     */
    public static String restriction() {
        return "instance='pgsql' AND ( " + Database.restriction() + " )";
    }
}
hsarback/src/de/hsadmin/mods/db/PgSqlDatabaseModuleImpl.java
New file
@@ -0,0 +1,41 @@
package de.hsadmin.mods.db;
import java.util.List;
import javax.persistence.EntityManager;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.AuthorisationException;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.mods.user.UnixUser;
public class PgSqlDatabaseModuleImpl extends AbstractModuleImpl {
    @Override
    public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass, String condition, String orderBy) throws HSAdminException {
        if (orderBy == null || orderBy.length() == 0) {
            orderBy = "ORDER BY name ASC";
        }
        return super.search(entityClass, condition, orderBy);
    }
    @Override
    public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
        EntityManager em = getTransaction().getEntityManager();
        UnixUser unixUser = getLoginUser();
        MySqlDatabase detachtedDB = (MySqlDatabase) existingEntity;
        MySqlDatabase attachedDB = em.find(MySqlDatabase.class, detachtedDB.getId());
        if (!attachedDB.getName().equals(detachtedDB.getName())) {
            throw new AuthorisationException(unixUser, "update", existingEntity, "name");
        }
        if (!attachedDB.getEncoding().equals(detachtedDB.getEncoding())) {
            throw new AuthorisationException(unixUser, "update", existingEntity, "encoding");
        }
        if (!attachedDB.getInstance().equals(detachtedDB.getInstance())) {
            throw new AuthorisationException(unixUser, "update", existingEntity, "instance");
        }
        return super.update(existingEntity);
    }
}
hsarback/src/de/hsadmin/mods/db/PgSqlDatabaseProcessorFactory.java
New file
@@ -0,0 +1,77 @@
package de.hsadmin.mods.db;
import javax.persistence.EntityManager;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.qserv.EntityProcessorFactory;
import de.hsadmin.core.qserv.Processor;
/**
 * Factory class which creates Processor instances for dealing with UNIX user
 * accounts.
 *
 * @author mi
 */
public class PgSqlDatabaseProcessorFactory implements EntityProcessorFactory {
    /**
     * creates a JDBCProcessor for PostgreSQL and the given user
     *
     * @param user
     * @param password
     * @return
     */
    public static JDBCProcessor createPostgreSqlProcessor(String user, String password) {
        return new JDBCProcessor("org.postgresql.Driver",
                "jdbc:postgresql://localhost/template1", user, password);
    }
    /**
     * creates a JDBCProcessor for the PostgreSQL admin user
     *
     * @return
     */
    public static JDBCProcessor createPostgreSqlAdminProcessor() {
        return new JDBCProcessor("org.postgresql.Driver", "jdbc:postgresql://localhost/template1");
    }
    /**
     * @return a Processor which creates a new database
     */
    public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity) {
        Database db = (Database) entity;
        assert db.getInstance().equals("pgsql");
        JDBCProcessor aJDBCP = null;
        String aName = AbstractEntity.escapeString(db.getName());
        String aOwner = AbstractEntity.escapeString(db.getOwner());
        String aEncoding = AbstractEntity.escapeString(db.getEncoding());
        aJDBCP = createPostgreSqlAdminProcessor();
        aJDBCP.addSQL("CREATE DATABASE " + aName + " OWNER=" + aOwner + " ENCODING='" + aEncoding + "' TEMPLATE template0");
        return aJDBCP;
    }
    /**
     * @return a Processor which updates a preexisting database
     */
    public <T extends AbstractEntity> Processor createUpdateProcessor(EntityManager em, T entity) {
        Database db = (Database) entity;
        assert db.getInstance().equals("pgsql");
        String aName = AbstractEntity.escapeString(db.getName());
        String aOwner = AbstractEntity.escapeString(db.getOwner());
        JDBCProcessor aJDBCP = null;
        aJDBCP = createPostgreSqlAdminProcessor();
        aJDBCP.addSQL("ALTER DATABASE " + aName + " OWNER TO " + aOwner);
        return aJDBCP;
    }
    /**
     * @return a Processor which deletes an existing database
     */
    public <T extends AbstractEntity> Processor createDeleteProcessor(EntityManager em, T entity) {
        Database db = (Database) entity;
        assert db.getInstance().equals("pgsql");
        JDBCProcessor aJDBCP = createPostgreSqlAdminProcessor();
        String aName = AbstractEntity.escapeString(db.getName());
        aJDBCP.addSQL("DROP DATABASE " + aName);
        return aJDBCP;
    }
}
hsarback/src/de/hsadmin/mods/db/PgSqlUser.java
New file
@@ -0,0 +1,42 @@
package de.hsadmin.mods.db;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
@Entity(name = "PgSqlUsers")
@Table(name = "database_user")
@SequenceGenerator(name = "DatabaseUserSeqGen", sequenceName = "dbuser_dbuser_id_seq")
@EntityInfo(name = "PostgreSQL Konto")
@SearchFilter("instance = 'pgsql' AND (" + "    pac = :loginUserPac OR "
        + "    pac.customer.memberCode = :loginUserName )")
public class PgSqlUser extends DatabaseUser implements Serializable {
    private static final long serialVersionUID = -1097602753310286629L;
    public static String createQueryFromStringKey(String humanKey) {
        return "name='" + humanKey + "' AND instance='pgsql'";
    }
    public PgSqlUser() {
        setInstance("pgsql");
    }
    public PgSqlUser(Pac pac, String name, String password) {
        super("pgsql", pac, name, password);
    }
    /**
     *  query restriction for access control
     */
    public static String restriction() {
        return "instance='pgsql' AND ( " + DatabaseUser.restriction() + " )";
    }
}
hsarback/src/de/hsadmin/mods/db/PgSqlUserModuleImpl.java
New file
@@ -0,0 +1,20 @@
package de.hsadmin.mods.db;
import java.util.List;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.HSAdminException;
public class PgSqlUserModuleImpl extends AbstractModuleImpl {
    @Override
    public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass,
            String condition, String orderBy) throws HSAdminException {
        if (orderBy == null || orderBy.length() == 0) {
            orderBy = "ORDER BY name ASC";
        }
        return super.search(entityClass, condition, orderBy);
    }
}
hsarback/src/de/hsadmin/mods/db/PgSqlUserProcessorFactory.java
New file
@@ -0,0 +1,48 @@
package de.hsadmin.mods.db;
import javax.persistence.EntityManager;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.qserv.EntityProcessorFactory;
import de.hsadmin.core.qserv.Processor;
/**
 * Factory class which creates Processor instances for dealing with UNIX user
 * accounts.
 *
 * @author mi
 */
public class PgSqlUserProcessorFactory implements EntityProcessorFactory {
    public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity) {
        DatabaseUser dbu = (DatabaseUser) entity;
        assert dbu.getInstance().equals("pgsql");
        JDBCProcessor aJDBCP = PgSqlDatabaseProcessorFactory.createPostgreSqlAdminProcessor();
        String aName = AbstractEntity.escapeString(dbu.getName());
        String aPassword = AbstractEntity.escapeString(dbu.getPassword());
        aJDBCP.addSQL("CREATE USER " + aName + " NOCREATEDB NOCREATEUSER" + " ENCRYPTED PASSWORD '" + aPassword + "'");
        return aJDBCP;
    }
    public <T extends AbstractEntity> Processor createUpdateProcessor(
            EntityManager em, T entity) {
        DatabaseUser dbu = (DatabaseUser) entity;
        assert dbu.getInstance().equals("pgsql");
        JDBCProcessor aJDBCP = PgSqlDatabaseProcessorFactory.createPostgreSqlAdminProcessor();
        String aName = AbstractEntity.escapeString(dbu.getName());
        String aPassword = AbstractEntity.escapeString(dbu.getPassword());
        aJDBCP.addSQL("ALTER USER " + aName + " WITH ENCRYPTED PASSWORD '" + aPassword + "'");
        return aJDBCP;
    }
    public <T extends AbstractEntity> Processor createDeleteProcessor(
            EntityManager em, T entity) {
        DatabaseUser dbu = (DatabaseUser) entity;
        assert dbu.getInstance().equals("pgsql");
        JDBCProcessor aJDBCP = PgSqlDatabaseProcessorFactory.createPostgreSqlAdminProcessor();
        String aName = AbstractEntity.escapeString(dbu.getName());
        aJDBCP.addSQL("DROP USER " + aName);
        return aJDBCP;
    }
}
hsarback/src/de/hsadmin/mods/dom/Domain.java
@@ -6,7 +6,10 @@
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
@@ -14,27 +17,30 @@
import javax.persistence.Temporal;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.mods.user.UnixUser;
@javax.persistence.Entity(name = "Domains")
@Entity(name = "Domains")
@Table(name = "domain")
@SequenceGenerator(name = "DomainsSeqGen", sequenceName = "domain_domain_id_seq")
public class Domain extends AbstractEntity {
    private static final long serialVersionUID = -7496110900868795840L;
    @javax.persistence.Id
    @javax.persistence.Column(name = "domain_id", columnDefinition = "integer")
    @javax.persistence.GeneratedValue(strategy = SEQUENCE, generator = "DomainsSeqGen")
    @Id
    @Column(name = "domain_id", columnDefinition = "integer")
    @GeneratedValue(strategy = SEQUENCE, generator = "DomainsSeqGen")
    private long id;
    @javax.persistence.Column(name = "domain_name", columnDefinition = "character varying(256)", nullable = false)
    @FieldValidation("[a-z0-9\\-\\.]*")
    @Column(name = "domain_name", columnDefinition = "character varying(256)", nullable = false)
    private String name;
    @JoinColumn(name = "domain_owner", columnDefinition = "integer", nullable = false)
    @ManyToOne(fetch = EAGER)
    private UnixUser user;
    @FieldValidation("[a-z]*")
    @Column(name = "domain_status", columnDefinition = "character varying(12)", nullable = false)
    private String status;
@@ -54,6 +60,7 @@
    @Temporal(javax.persistence.TemporalType.DATE)
    private Date until;
    @FieldValidation("[a-z0-9\\-\\.]*")
    @Column(name = "domain_dns_master", columnDefinition = "character varying(64)")
    private String dnsMaster;
@@ -105,7 +112,6 @@
        this.user = user;
    }
    @javax.persistence.Transient
    public Status getStatus() {
        return Status.valueFor(status);
    }
hsarback/src/de/hsadmin/mods/email/EMailAddress.java
@@ -18,6 +18,7 @@
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.dom.Domain;
@@ -42,9 +43,11 @@
    @Column(name = "emailaddr_id", columnDefinition = "integer")
    private long id;
    
    @FieldValidation("[A-Za-z0-9\\_\\-\\.\\+]*")
    @Column(name = "localpart", updatable = false, nullable= false)
    private String localpart = "";
    
    @FieldValidation("[a-z0-9\\-\\.]*")
    @Column(name = "subdomain")
    private String subdomain;
    
@@ -52,15 +55,16 @@
    @JoinColumn(name = "domain_id", columnDefinition = "integer", updatable = false)
    private Domain domain;
    
    @FieldValidation("[a-zA-Z0-9\\_\\-\\.\\|\\\"\\/\\@\\,\\+]*")
    @Column(name = "target", nullable= false)
    private String target;
    public EMailAddress() {
    }
    public EMailAddress(String localPart, String subdomain, Domain domain,
    public EMailAddress(String localpart, String subdomain, Domain domain,
            String target) {
        this.localpart = localPart;
        this.localpart = localpart;
        this.subdomain = subdomain;
        this.domain = domain;
        this.target = target;
@@ -92,7 +96,7 @@
    @Override
    public String createStringKey() {
        String key = getDomain() != null ? (getLocalPart() + "@" + getFullDomain())
        String key = getDomain() != null ? (getLocalpart() + "@" + getFullDomain())
                : "?@?";
        return key;
    }
@@ -110,12 +114,12 @@
        this.id = id;
    }
    public String getLocalPart() {
    public String getLocalpart() {
        return localpart == null ? "" : localpart;
    }
    public void setLocalPart(String localPart) {
        this.localpart = trimToEmpty(localPart);
    public void setLocalpart(String localpart) {
        this.localpart = trimToEmpty(localpart);
    }
    public String getSubdomain() {
hsarback/src/de/hsadmin/mods/email/EMailAddressModuleImpl.java
@@ -29,8 +29,8 @@
        if (adr.getTarget() == null || adr.getTarget().length() == 0) {
            throw new HSAdminException("target required");
        }
        if (adr.getLocalPart() == null) {
            adr.setLocalPart("");
        if (adr.getLocalpart() == null) {
            adr.setLocalpart("");
        }
        if (adr.getDomain() == null
                || adr.getDomain().getName() == null
@@ -59,9 +59,9 @@
            detachedAddr.setSubdomain(attachedAddr.getSubdomain());
            throw new AuthorisationException(getLoginUser(), "update", detachedAddr, "subdomain");
        }
        String localPart = detachedAddr.getLocalPart();
        if (localPart != null && !localPart.equals(attachedAddr.getLocalPart())) {
            detachedAddr.setLocalPart(attachedAddr.getLocalPart());
        String localPart = detachedAddr.getLocalpart();
        if (localPart != null && !localPart.equals(attachedAddr.getLocalpart())) {
            detachedAddr.setLocalpart(attachedAddr.getLocalpart());
            throw new AuthorisationException(getLoginUser(), "update", detachedAddr, "localpart");
        }
        String target = detachedAddr.getTarget();
hsarback/src/de/hsadmin/mods/email/EMailAlias.java
@@ -15,9 +15,10 @@
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
@@ -44,9 +45,11 @@
    @JoinColumn(name = "pac_id", columnDefinition = "integer")
    private Pac pac;
    @FieldValidation("[a-z0-9\\_\\-\\.\\+]*")
    @Column(updatable=false)
    private String name;
    @FieldValidation("[a-zA-Z0-9\\_\\-\\.\\|\\\"\\/\\@\\,\\+\\ ]*")
    @Column
    private String target;
hsarback/src/de/hsadmin/mods/pac/BaseComponent.java
@@ -15,7 +15,7 @@
import de.hsadmin.mods.user.UnixUser;
@Entity(name = "BaseComponents")
@Table(name = " basecomponent")
@Table(name = "basecomponent")
@SequenceGenerator(name = "BaseComponentsSeqGen", sequenceName = "basecomponent_basecomponent_seq")
public class BaseComponent extends de.hsadmin.core.model.AbstractEntity implements Serializable {
    
@@ -24,7 +24,7 @@
    @Id
    @GeneratedValue(strategy = SEQUENCE, generator = "BaseComponentsSeqGen")
    @Column(name = "basecomponent_id", columnDefinition = "integer")
    private long id;
    private long baseComponentId;
    @Column(name = "basecomponent_code", columnDefinition = "character varying(10)")
    private String feature;
@@ -59,15 +59,7 @@
    @Override
    public long id() {
        return id;
    }
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
        return baseComponentId;
    }
    public String getFeature() {
@@ -104,11 +96,19 @@
    @Override
    public boolean isNew() {
        return id == 0;
        return baseComponentId == 0;
    }
    @Override
    public UnixUser owningUser(EntityManager em) {
        return null; // TODO: kinda somebody like root needed
    }
    public void setBaseComponentId(long baseComponentId) {
        this.baseComponentId = baseComponentId;
    }
    public long getBaseComponentId() {
        return baseComponentId;
    }
}
hsarback/src/de/hsadmin/mods/pac/BasePac.java
@@ -38,7 +38,7 @@
    @Id
    @GeneratedValue(strategy = SEQUENCE, generator = "BasePacsSeqGen")
    @Column(name = "basepacket_id", columnDefinition = "integer")
    private long id;
    private long basePacId;
    @Column(name = "basepacket_code", columnDefinition = "character varying(10)")
    private String name;
@@ -59,12 +59,16 @@
    @JoinTable(name = "packet_component", joinColumns = @JoinColumn(name = "packet_id"), inverseJoinColumns = @JoinColumn(name = "basepacket_id"))
    private Set<Pac> pacs;
    public long getId() {
        return id;
    public long id() {
        return basePacId;
    }
    public void setId(long id) {
        this.id = id;
    public long getBasePacId() {
        return basePacId;
    }
    public void setBasePacId(long id) {
        this.basePacId = id;
    }
    public String getName() {
@@ -136,7 +140,7 @@
        if (aOther == null || aOther.getClass() != getClass())
            return false;
        BasePac aOtherBP = (BasePac) aOther;
        if (id != aOtherBP.id)
        if (basePacId != aOtherBP.basePacId)
            return false;
        if (name != null && !name.equals(aOtherBP.name))
            return false;
hsarback/src/de/hsadmin/mods/pac/Component.java
@@ -6,6 +6,8 @@
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity(name = "Components")
@@ -16,9 +18,19 @@
    private static final long serialVersionUID = 970709621200712794L;
    @Id
    @Column(name="basepacket_id", insertable=false, updatable=false)
    private long basePacId;
    @Id
    @Column(name="basecomponent_id", insertable=false, updatable=false)
    private long baseComponentId;
    @ManyToOne
    @JoinColumn(name="basepacket_id")
    private BasePac basePac;
    
    @Id
    @ManyToOne
    @JoinColumn(name="basecomponent_id")
    private BaseComponent baseComponent;
    
    @Column(name = "min_quantity", columnDefinition = "integer")
@@ -44,7 +56,9 @@
    public Component(BasePac basePac, BaseComponent baseComp, int min, int max,
            int def, int incr, int incl, boolean adminOnly) {
        this.setBasePacId(basePac.id());
        this.basePac = basePac;
        this.setBaseComponentId(baseComp.id());
        this.baseComponent = baseComp;
        this.minimumQuantity = min;
        this.maximimumQuantity = max;
@@ -59,6 +73,7 @@
    }
    public void setBasePac(BasePac basePac) {
        this.setBasePacId(basePac.id());
        this.basePac = basePac;
    }
@@ -67,6 +82,7 @@
    }
    public void setBaseComponent(BaseComponent baseComponent) {
        this.setBaseComponentId(baseComponent.id());
        this.baseComponent = baseComponent;
    }
@@ -118,4 +134,20 @@
        this.adminOnly = adminOnly;
    }
    public void setBasePacId(long basePacId) {
        this.basePacId = basePacId;
    }
    public long getBasePacId() {
        return basePacId;
    }
    public void setBaseComponentId(long baseComponentId) {
        this.baseComponentId = baseComponentId;
    }
    public long getBaseComponentId() {
        return baseComponentId;
    }
}
hsarback/src/de/hsadmin/mods/pac/ComponentId.java
@@ -1,22 +1,51 @@
package de.hsadmin.mods.pac;
public class ComponentId {
import java.io.Serializable;
    public long basePac;
    public long baseComponent;
public class ComponentId implements Serializable {
    private static final long serialVersionUID = 6213446997257985587L;
    private long basePacId;
    private long baseComponentId;
    public ComponentId() {
    }
    public ComponentId(long basePacId, long baseComponentId) {
        this.setBasePacId(basePacId);
        this.setBaseComponentId(baseComponentId);
    }
    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof ComponentId) {
            ComponentId other = (ComponentId) obj;
            return basePac == other.basePac && baseComponent == other.baseComponent;
            return getBasePacId() == other.getBasePacId() && getBaseComponentId() == other.getBaseComponentId();
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        return (new Long(basePac ^ baseComponent % Integer.MAX_VALUE)).intValue();
        return (new Long(getBasePacId() ^ getBaseComponentId() % Integer.MAX_VALUE)).intValue();
    }
    public void setBasePacId(long basePacId) {
        this.basePacId = basePacId;
    }
    public long getBasePacId() {
        return basePacId;
    }
    public void setBaseComponentId(long baseComponentId) {
        this.baseComponentId = baseComponentId;
    }
    public long getBaseComponentId() {
        return baseComponentId;
    }
}
hsarback/src/de/hsadmin/mods/pac/INetAddress.java
@@ -27,7 +27,7 @@
    @Column(name = "inet_addr_id")
    private long id;
    @Column(name = "inet_addr", columnDefinition = "inet", unique = true)
    @Column(name = "inet_addr", unique = true, length=-1)
    private String inetAddr;
    @Column(name = "description", columnDefinition = "character varying(100)")
hsarback/src/de/hsadmin/mods/pac/Pac.java
@@ -7,6 +7,8 @@
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -73,13 +75,17 @@
    @ManyToOne(fetch = EAGER)
    private INetAddress oldINetAddr;
    @OneToMany(fetch = LAZY, cascade = ALL)
    private java.util.Set<PacComponent> pacComponents;
    @OneToMany(fetch = LAZY, cascade = ALL, mappedBy="pac")
    private Set<PacComponent> pacComponents;
    @OneToMany(fetch = LAZY, cascade = ALL, mappedBy = "pac")
    private java.util.Set<UnixUser> unixUser;
    @OneToMany(fetch = LAZY, cascade = ALL, mappedBy="pac")
    private Set<UnixUser> unixUser;
    @Transient
    private BasePac basepac;
    public Pac() {
        basepac = null;
    }
    public Pac(String name, Customer cust, BasePac basePac, Hive hive) {
@@ -87,12 +93,12 @@
        this.customer = cust;
        this.hive = hive;
        this.created = new java.util.Date();
        this.created = new Date();
        this.webserverGroup = "httpd";
        this.curINetAddr = hive.getInetAddr();
        pacComponents = new java.util.HashSet<PacComponent>();
        java.util.Date today = new java.util.Date();
        pacComponents = new HashSet<PacComponent>();
        Date today = new Date();
        for (Component comp : basePac.getComponents()) {
            PacComponent pacComp = new PacComponent(basePac,
                    comp.getBaseComponent(), this, comp.getDefaultQuantity(),
@@ -197,32 +203,25 @@
        this.oldINetAddr = oldINetAddr;
    }
    // virtual attribute basePac
    /*
     * This does not work, JPA/Hibernate always wants to create an invalid row
     * in packet_component
     *
     * @ManyToOne(fetch=EAGER, optional=true) // optional
     * should be default anyway
     *
     * @JoinTable( name="packet_component",
     * joinColumns=@JoinColumn(name="packet_id"),
     * inverseJoinColumns=@JoinColumn(name="basepacket_id") )
     */
    @Transient
    public BasePac getBasePac() {
        return getPacComponents().iterator().next().getBasePac();
    public BasePac getBasepac() {
        if (basepac == null) {
            Set<PacComponent> pacComps = getPacComponents();
            if (pacComps != null) {
                basepac = pacComps.iterator().next().getBasePac();
            }
        }
        return basepac;
    }
    public void setBasePac(BasePac basePac) {
        // TODO: needs code to change basePac in all pacComponents
    public void setBasepac(BasePac basepac) {
        this.basepac = basepac;
    }
    public java.util.Set<PacComponent> getPacComponents() {
    public Set<PacComponent> getPacComponents() {
        return pacComponents;
    }
    public void setPacComponents(java.util.Set<PacComponent> pacComponents) {
    public void setPacComponents(Set<PacComponent> pacComponents) {
        this.pacComponents = pacComponents;
    }
@@ -233,11 +232,11 @@
        return null;
    }
    public java.util.Set<UnixUser> getUnixUser() {
    public Set<UnixUser> getUnixUser() {
        return unixUser;
    }
    public void setUnixUser(java.util.Set<UnixUser> unixUser) {
    public void setUnixUser(Set<UnixUser> unixUser) {
        this.unixUser = unixUser;
    }
@@ -264,7 +263,6 @@
    }
    public UnixUser getAdminUser(EntityManager em) {
        // TODO Auto-generated method stub
        return null;
    }
hsarback/src/de/hsadmin/mods/pac/PacComponent.java
@@ -1,8 +1,5 @@
package de.hsadmin.mods.pac;
import static javax.persistence.FetchType.EAGER;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
@@ -18,18 +15,30 @@
@Entity(name = "PacComponents")
@Table(name = "packet_component")
@IdClass(PacComponentId.class)
public class PacComponent implements Serializable {
public class PacComponent {
    
    private static final long serialVersionUID = 5359873462163274873L;
    @Id
    @Column(name="packet_id", insertable=false, updatable=false, columnDefinition = "integer")
    private long pacId;
    @Id
    @Column(name="basepacket_id", insertable=false, updatable=false, columnDefinition = "integer")
    private long basePacId;
    @Id
    @Column(name="basecomponent_id", insertable=false, updatable=false, columnDefinition = "integer")
    private long baseComponentId;
    @ManyToOne
    @JoinColumn(name = "packet_id")
    private Pac pac;
    
    @Id
    @ManyToOne
    @JoinColumn(name = "basecomponent_id")
    private BaseComponent baseComponent;
    @JoinColumn(name = "basepacket_id", columnDefinition = "integer", nullable = false)
    @ManyToOne(fetch = EAGER)
    @ManyToOne
    @JoinColumn(name = "basepacket_id")
    private BasePac basePac;
    @Column(name = "quantity", columnDefinition = "integer")
@@ -104,4 +113,28 @@
        this.cancelled = cancelled;
    }
    public void setPacId(long pacId) {
        this.pacId = pacId;
    }
    public long getPacId() {
        return pacId;
    }
    public void setBaseComponentId(long baseComponentId) {
        this.baseComponentId = baseComponentId;
    }
    public long getBaseComponentId() {
        return baseComponentId;
    }
    public void setBasePacId(long basePacId) {
        this.basePacId = basePacId;
    }
    public long getBasePacId() {
        return basePacId;
    }
}
hsarback/src/de/hsadmin/mods/pac/PacComponentId.java
@@ -1,23 +1,53 @@
package de.hsadmin.mods.pac;
import java.io.Serializable;
public class PacComponentId {
    public long pac;
    public long baseComponent;
public class PacComponentId implements Serializable {
    private static final long serialVersionUID = -3018368675798315892L;
    private long pacId;
    private long basePacId;
    private long baseComponentId;
    
    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof PacComponentId) {
            PacComponentId other = (PacComponentId) obj;
            return pac == other.pac && baseComponent == other.baseComponent;
            return getPacId() == other.getPacId() && getBaseComponentId() == other.getBaseComponentId() && getBasePacId() == other.getBasePacId();
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        return (new Long(pac ^ baseComponent % Integer.MAX_VALUE)).intValue();
        return (new Long(getPacId() ^ getBaseComponentId() ^ getBasePacId() % Integer.MAX_VALUE)).intValue();
    }
    public void setPacId(long pacId) {
        this.pacId = pacId;
    }
    public long getPacId() {
        return pacId;
    }
    public void setBaseComponentId(long baseComponentId) {
        this.baseComponentId = baseComponentId;
    }
    public long getBaseComponentId() {
        return baseComponentId;
    }
    public void setBasePacId(long basePacId) {
        this.basePacId = basePacId;
    }
    public long getBasePacId() {
        return basePacId;
    }
}
hsarback/src/de/hsadmin/mods/pac/PacModuleImpl.java
New file
@@ -0,0 +1,83 @@
package de.hsadmin.mods.pac;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.mods.cust.Customer;
public class PacModuleImpl extends AbstractModuleImpl {
    @Override
    public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass,
            String condition, String orderBy) throws HSAdminException {
        if (orderBy == null || orderBy.length() == 0) {
            orderBy = "ORDER BY obj.name ASC";
        }
        return super.search(entityClass, condition, orderBy);
    }
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        Date now = new Date();
        EntityManager em = getTransaction().getEntityManager();
        Pac pac = (Pac) newEntity;
        BasePac basepac = pac.getBasepac();
        if (basepac == null || basepac.getName() == null || basepac.getName().length() == 0) {
            throw new HSAdminException("basepac required");
        }
        Query qBasepac = em.createQuery("SELECT b FROM BasePacs b WHERE b.name = :basepacName AND b.valid = :valid");
        qBasepac.setParameter("basepacName", basepac.getName());
        qBasepac.setParameter("valid", Boolean.TRUE);
        basepac = (BasePac) qBasepac.getSingleResult();
        pac.setBasepac(basepac);
        Query qComponents = em.createQuery("SELECT c FROM Components c WHERE c.basePacId = :basepac");
        qComponents.setParameter("basepac", basepac.id());
        INetAddress curINetAddr = pac.getCurINetAddr();
        if (curINetAddr == null || curINetAddr.getInetAddr() == null || curINetAddr.getInetAddr().length() == 0) {
            throw new HSAdminException("curinetaddr required");
        }
        Query qINetAddr = em.createNativeQuery("SELECT * FROM inet_addr WHERE inet_addr = inet '" + curINetAddr.getInetAddr() + "'", INetAddress.class);
        curINetAddr = (INetAddress) qINetAddr.getSingleResult();
        pac.setCurINetAddr(curINetAddr);
        Customer customer = pac.getCustomer();
        if (customer == null || customer.getName() == null || customer.getName().length() == 0) {
            throw new HSAdminException("customer required");
        }
        Query qCustomer = em.createQuery("SELECT c FROM Customers c WHERE c.name = :name");
        qCustomer.setParameter("name", customer.getName());
        customer = (Customer) qCustomer.getSingleResult();
        pac.setCustomer(customer);
        Hive hive = pac.getHive();
        if (hive == null || hive.getName() == null || hive.getName().length() == 0) {
            throw new HSAdminException("hive required");
        }
        Query qHive = em.createQuery("SELECT h FROM Hives h WHERE h.name = :name");
        qHive.setParameter("name", hive.getName());
        hive = (Hive) qHive.getSingleResult();
        pac.setHive(hive);
//        em.persist(newEntity);
        List<?> componentsList = qComponents.getResultList();
        Set<PacComponent> pacComponents = new HashSet<PacComponent>();
        for (Object cObj : componentsList) {
            Component comp = (Component) cObj;
            PacComponent pacComponent = new PacComponent();
            pacComponent.setBaseComponent(comp.getBaseComponent());
            pacComponent.setbasePac(comp.getBasePac());
            pacComponent.setCreated(now);
            pacComponent.setPac(pac);
            pacComponent.setQuantity(comp.getDefaultQuantity());
//            em.persist(pacComponent);
        }
        pac.setPacComponents(pacComponents);
        return super.add(newEntity);
    }
}
hsarback/src/de/hsadmin/mods/user/UnixUser.java
@@ -17,6 +17,7 @@
import javax.persistence.Transient;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.mods.pac.Pac;
@Entity(name = "UnixUsers")
@@ -36,9 +37,11 @@
    @Column(name = "userid", columnDefinition = "integer", nullable = false, updatable=false)
    private long userId;
    @FieldValidation("[a-z0-9\\_\\-\\.]*")
    @Column(name = "name", columnDefinition = "character varying(24)", unique = true, updatable=false)
    private String name;
    @FieldValidation("[^:]*")
    @Transient
    private String password;
@@ -46,12 +49,15 @@
    @ManyToOne(fetch = EAGER)
    private Pac pac;
    @FieldValidation("[a-zA-Z0-9\\_\\-\\.\\,\\ ]*")
    @Column(name = "comment", columnDefinition = "character varying(128)")
    private String comment;
    @FieldValidation("[a-z\\/]*")
    @Column(name = "shell", columnDefinition = "character varying(32)")
    private String shell;
    @FieldValidation("[a-z0-9\\/\\_\\-\\.]*")
    @Column(name = "homedir", columnDefinition = "character varying(48)", updatable=false)
    private String homedir;
hsarback/src/de/hsadmin/remote/EMailAddressRemote.java
@@ -16,7 +16,7 @@
        String admin = adr.getDomain().getUser().getName();
        String pac = adr.getDomain().getUser().getPac().getName();
        String target = adr.getTarget();
        String localpart = adr.getLocalPart();
        String localpart = adr.getLocalpart();
        String subdomain = adr.getSubdomain();
        String emailaddress = adr.getEMailAddress();
        String fulldomain = adr.getFullDomain();
@@ -34,9 +34,9 @@
    @Override
    protected void map2entity(Map<String, String> map, AbstractEntity entity) {
        EMailAddress adr = (EMailAddress) entity;
        String localPart = map.get("localpart");
        if (assertNotNull(localPart)) {
            adr.setLocalPart(localPart);
        String localpart = map.get("localpart");
        if (assertNotNull(localpart)) {
            adr.setLocalpart(localpart);
        }
        String subdomain = map.get("subdomain");
        if (assertNotNull(subdomain)) {
hsarback/src/de/hsadmin/remote/PacRemote.java
New file
@@ -0,0 +1,75 @@
package de.hsadmin.remote;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.mods.cust.Customer;
import de.hsadmin.mods.pac.BasePac;
import de.hsadmin.mods.pac.Hive;
import de.hsadmin.mods.pac.INetAddress;
import de.hsadmin.mods.pac.Pac;
public class PacRemote extends AbstractRemote {
    private static final DateFormat df = SimpleDateFormat.getDateInstance(DateFormat.SHORT);
    @Override
    protected void entity2map(AbstractEntity entity, Map<String, String> resultMap) {
        Pac pac = (Pac) entity;
        resultMap.put("name", pac.getName());
        resultMap.put("id", Long.toString(pac.getId()));
        resultMap.put("hive", pac.getHiveName());
        resultMap.put("customer", pac.getCustomer().getName());
        resultMap.put("curinetaddr", pac.getCurINetAddr().getInetAddr());
        resultMap.put("created", df.format(pac.getCreated()));
    }
    @Override
    protected Class<? extends AbstractEntity> getEntityClass() {
        return Pac.class;
    }
    @Override
    protected void map2entity(Map<String, String> setParams, AbstractEntity entity) {
        Pac pac = (Pac) entity;
        BasePac basePac = pac.getBasepac();
        String basePacName = setParams.get("basepac");
        if (basePac == null && assertNotNull(basePacName)) {
            basePac = new BasePac();
            basePac.setName(basePacName);
            pac.setBasepac(basePac);
        }
        pac.setCreated(new Date());
        INetAddress curINetAddr = pac.getCurINetAddr();
        String inetAddrString = setParams.get("curinetaddr");
        if (curINetAddr == null && assertNotNull(inetAddrString)) {
            curINetAddr = new INetAddress(inetAddrString);
            pac.setCurINetAddr(curINetAddr);
        }
        Customer customer = pac.getCustomer();
        String memberCode = setParams.get("customer");
        if (customer == null && assertNotNull(memberCode)) {
            customer = new Customer();
            customer.setName(memberCode);
            pac.setCustomer(customer);
        }
        Hive hive = pac.getHive();
        String hiveName = setParams.get("hive");
        if (hive == null && assertNotNull(hiveName)) {
            hive = new Hive();
            hive.setName(hiveName);
            pac.setHive(hive);
        }
        pac.setName(setParams.get("name"));
    }
    @Override
    protected void regularizeKeys(Map<String, String> whereParams) {
        replaceKey(whereParams, "customer", "customer.name");
        replaceKey(whereParams, "basepac", "customer.name");
    }
}
hsarback/src/org/apache/xmlrpc/webserver/XmlRpcServlet.properties
@@ -1,4 +1,5 @@
member=de.hsadmin.remote.CustomerRemote
pac=de.hsadmin.remote.PacRemote
user=de.hsadmin.remote.UnixUserRemote
domain=de.hsadmin.remote.DomainRemote
emailalias=de.hsadmin.remote.EMailAliasRemote
hsarback/test/de/hsadmin/remote/DomainTest.java
@@ -45,7 +45,7 @@
        try {
            Object execute = client.execute(MODULE + ".search", params);
            Object[] result = (Object[]) execute;
            assertEquals(36, result.length);
            assertEquals(29, result.length);
            for (Object o : result) {
                if (o instanceof Map<?, ?>) {
                    Map<?, ?> row = (Map<?, ?>) o;
@@ -66,7 +66,7 @@
        Map<String, String> setParams = new HashMap<String, String>();
        Map<String, String> whereParams = new HashMap<String, String>();
        setParams.put("user", "peh00-phor");
        whereParams.put("name", "i2null.de");
        whereParams.put("name", "smb-linn.de");
        Object[] params = new Object[] { user, 
                cas.getServiceTicket(grantingTicketURL, RemoteTestHelper.getBackendURL()), 
                setParams, whereParams };
hsarback/test/de/hsadmin/remote/EMailAddressTest.java
@@ -44,7 +44,7 @@
        try {
            Object execute = client.execute(MODULE + ".search", params);
            Object[] result = (Object[]) execute;
            assertEquals(253, result.length);
            assertEquals(242, result.length);
            for (Object o : result) {
                if (o instanceof Map<?, ?>) {
                    Map<?, ?> row = (Map<?, ?>) o;
@@ -204,9 +204,13 @@
            Object[] resArray = (Object[]) execute;
            assertEquals(1, resArray.length);
            Object res = resArray[0];
            Map<String, Object> map = (Map<String, Object>) res;
            Object idVal = map.get("id");
            whereParams.put("id", idVal);
            if (res instanceof Map<?, ?>) {
                Map<?, ?> map = (Map<?, ?>) res;
                Object idVal = map.get("id");
                whereParams.put("id", idVal);
            } else {
                fail("unexpected type");
            }
        } catch (XmlRpcException e) {
            fail(e.getMessage());
        }
hsarback/test/de/hsadmin/remote/PacTest.java
New file
@@ -0,0 +1,144 @@
package de.hsadmin.remote;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.HashMap;
import java.util.Map;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class PacTest {
    private static final String MODULE = "pac";
    private XmlRpcClient client;
    private RemoteCASHelper cas;
    @Before
    public void setUp() throws Exception {
        client = RemoteTestHelper.getClient();
        cas = new RemoteCASHelper();
    }
    @After
    public void tearDown() throws Exception {
        client = null;
        cas = null;
    }
    @Test
    public void testSearchAllAsPacAdmin() {
        String user = "peh00";
        String grantingTicketURL = cas.getGrantingTicketURL(user);
        Map<String, String> whereParams = new HashMap<String, String>();
        Object[] params = new Object[] { user,
                cas.getServiceTicket(grantingTicketURL, RemoteTestHelper.getBackendURL()),
                whereParams };
        try {
            Object execute = client.execute(MODULE + ".search", params);
            Object[] result = (Object[]) execute;
            assertEquals(1, result.length);
            for (Object o : result) {
                if (o instanceof Map<?, ?>) {
                    Map<?, ?> row = (Map<?, ?>) o;
                    assertEquals("hsh00-peh", row.get("customer"));
                } else {
                    fail("map expected");
                }
            }
        } catch (XmlRpcException e) {
            fail(e.getMessage());
        }
    }
    @Test
    public void testUpdate() {
        String user = "peh00";
        String grantingTicketURL = cas.getGrantingTicketURL(user);
        Map<String, String> setParams = new HashMap<String, String>();
        Map<String, String> whereParams = new HashMap<String, String>();
        setParams.put("curinetaddr", "192.168.10.2");
        whereParams.put("name", "peh00");
        Object[] params = new Object[] { user,
                cas.getServiceTicket(grantingTicketURL, RemoteTestHelper.getBackendURL()),
                setParams, whereParams };
        try {
            Object execute = client.execute(MODULE + ".update", params);
            assertNotNull(execute);
            fail("exception expected");
        } catch (XmlRpcException e) {
//            System.out.println(e.getMessage());
        }
    }
    @Test
    public void testCreate() {
        int count = getPacsCount();
        String user = "pe";
        String grantingTicketURL = cas.getGrantingTicketURL(user);
        Map<String, String> setParams = new HashMap<String, String>();
        setParams.put("name", "peh07");
        setParams.put("hive", "h05");
        setParams.put("customer", "hsh00-peh");
        setParams.put("basepac", "DW/S");
        setParams.put("curinetaddr", "212.42.230.178");
        Object[] params = new Object[] { user,
                cas.getServiceTicket(grantingTicketURL, RemoteTestHelper.getBackendURL()),
                setParams };
        try {
            Object execute = client.execute(MODULE + ".add", params);
            assertTrue(execute instanceof Map<?, ?>);
        } catch (XmlRpcException e) {
            fail(e.getMessage());
        }
        assertEquals(count + 1, getPacsCount());
    }
    @Test
    public void testDelete() {
        int count = getPacsCount();
        String user = "pe";
        String grantingTicketURL = cas.getGrantingTicketURL(user);
        Map<String, String> whereParams = new HashMap<String, String>();
        whereParams.put("name", "peh07");
        Object[] params = new Object[] { user,
                cas.getServiceTicket(grantingTicketURL, RemoteTestHelper.getBackendURL()),
                whereParams };
        try {
            Object execute = client.execute(MODULE + ".delete", params);
            assertNull(execute);
        } catch (XmlRpcException e) {
            fail(e.getMessage());
        }
        assertEquals(count - 1, getPacsCount());
    }
    private int getPacsCount() {
        int count = 0;
        String user = "pe";
        String grantingTicketURL = cas.getGrantingTicketURL(user);
        Map<String, String> whereParams = new HashMap<String, String>();
        whereParams.put("customer", "hsh00-peh");
        Object[] params = new Object[] { user,
                cas.getServiceTicket(grantingTicketURL, RemoteTestHelper.getBackendURL()),
                whereParams };
        try {
            Object execute = client.execute(MODULE + ".search", params);
            Object[] result = (Object[]) execute;
            count = result.length;
        } catch (XmlRpcException e) {
            fail(e.getMessage());
        }
        return count;
    }
}
hsarback/test/de/hsadmin/remote/UnixUserTest.java
@@ -43,7 +43,7 @@
        try {
            Object execute = client.execute(MODULE + ".search", params);
            Object[] result = (Object[]) execute;
            assertEquals(22, result.length);
            assertEquals(21, result.length);
            for (Object o : result) {
                if (o instanceof Map<?, ?>) {
                    Map<?, ?> row = (Map<?, ?>) o;