Juan Hernandez has uploaded a new change for review. Change subject: [WIP] Introduce new directory interface ......................................................................
[WIP] Introduce new directory interface This change introduces a new Directory interface that represents the connection between the engine and a generic directory server, like LDAP, for example, but without the LDAP specific concepts that we currently use. It also introduces the DirectoryManager class that is responsible for loading implementations of the Directory class using the Java service provider mechanism, so they will be pluggable. Note that at the moment the new classes introduced by this change are not used anywhere, they are intended to make the engine less dependent on LDAP concepts, but that will happen in other changes. Note also that this change doesn't introduce any implementation of the interfaces, that will come in other changes as well. Change-Id: If84a0c9d6553d81cdbbe224972696f169cca90d4 Signed-off-by: Juan Hernandez <juan.hernan...@redhat.com> --- A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/directory/DirectoryManager.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/directory/DirectorySpi.java A backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/Directory.java A backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryEntry.java A backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryEntryStatus.java A backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryGroup.java A backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryUser.java 7 files changed, 506 insertions(+), 0 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/96/15596/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/directory/DirectoryManager.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/directory/DirectoryManager.java new file mode 100644 index 0000000..fd20c98 --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/directory/DirectoryManager.java @@ -0,0 +1,109 @@ +package org.ovirt.engine.core.bll.directory; + +import java.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.ovirt.engine.core.common.users.Directory; + +/** + * The directory manager is responsible for managing a collection of directory + * objects, like LDAP directories, for example. + * + * Directory implementations are loaded using the {@link ServiceLoader} class, + * so if you want to add a new one you will need to create the class that + * implements this interface and a file named + * <code>org.ovirt.engine.core.bll.directory.DirectorySpi</code> inside the + * <code>META-INF/services</code> directory of your jar file. The content of + * this file should be the fully qualified class name. + */ +public class DirectoryManager { + // The log: + private static final Logger log = Logger.getLogger(DirectoryManager.class); + + // This is a singleton, and this is the instance: + private static volatile DirectoryManager instance; + + /** + * Get an instance of the directory manager. + */ + public static DirectoryManager getInstance() { + if (instance == null) { + synchronized(DirectoryManager.class) { + if (instance == null) { + instance = new DirectoryManager(); + } + } + } + return instance; + } + + // Here we store the set of directory implementations loaded from the class + // path using the service loader mechanism: + private List<DirectorySpi> implementations = new ArrayList<>(2); + + /** + * Create the singleton. This constructor is not intended to be used outside + * of this class. + */ + private DirectoryManager() { + loadImplementations(); + } + + /** + * Loads the directory implementations that are available in the class path + * using the service loader mechanism. + */ + private void loadImplementations() { + ServiceLoader<DirectorySpi> loader = + ServiceLoader.load(DirectorySpi.class); + for (DirectorySpi implementation : loader) { + implementations.add(implementation); + log.info( + "Loaded directory implementation \"" + + implementation.getClass().getName() + "\"." + ); + } + } + + /** + * Returns the list of directories managed by all the directory + * implementations that have been previously loaded. + */ + public List<Directory> getDirectories() { + List<Directory> directories = new ArrayList<Directory>(); + for (DirectorySpi implementation : implementations) { + directories.addAll(implementation.getDirectories()); + } + return directories; + } + + /** + * Gets the directory instance that manages the directory for the given + * name. + * + * @param name the name of the directory + * @return the requested directory instance or <code>null</code> if no such + * implementation can be found + */ + public Directory getDirectory(String name) { + // Try with all the implementations and all the directories supported + // by each of them: + for (DirectorySpi implementation : implementations) { + for (Directory directory : implementation.getDirectories()) { + if (StringUtils.equals(directory.getName(), name)) { + return directory; + } + } + } + + // No luck, no directory matches the given name: + log.warn( + "There is no instance to manage directory \"" + name + "\", will " + + "return null." + ); + return null; + } +} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/directory/DirectorySpi.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/directory/DirectorySpi.java new file mode 100644 index 0000000..fdf455b --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/directory/DirectorySpi.java @@ -0,0 +1,17 @@ +package org.ovirt.engine.core.bll.directory; + +import java.util.List; + +import org.ovirt.engine.core.common.users.Directory; + +/** + * This interface is to be implemented by the classes that provide access to + * directory services. Each of these implementations can support a set of + * directories. + */ +public interface DirectorySpi { + /** + * Retrieves the set of directories managed by this implementation. + */ + List<Directory> getDirectories(); +} diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/Directory.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/Directory.java new file mode 100644 index 0000000..5527b56 --- /dev/null +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/Directory.java @@ -0,0 +1,85 @@ +package org.ovirt.engine.core.common.users; + +import java.util.Set; + +import org.ovirt.engine.core.compat.Guid; + +/** + * A directory is an object that manages a collection of users and groups, + * usually stored in an external system like an LDAP database. + */ +public interface Directory { + /** + * Returns the name of the directory, which usually is the name of the + * underlying domain, for example, for an LDAP directory the name should be + * based on the suffix of the LDAP database, so if the suffix is + * dc=example,dc=com then the name should be example.com. However this is + * not enforced at all, implementations can use whatever they find + * suitable. + */ + String getName(); + + /** + * Retrieves an user from the directory given its name. The name is expected + * to be unique. + * + * @param name the name of the user + * @return the user corresponding to the given name or + * <code>null</code> if no such user can be found + */ + DirectoryUser findUserByName(String name); + + /** + * Retrieves an user from the directory given its identifier. Note that this + * identifier is the one assigned by the engine to the user, not the one + * used by the directory itself. It is the responsibility of the directory + * implementation to translate this identifier in whatever the actual + * directory needs. + * + * @param id the identifier of the user + * @return the user corresponding to the given identifier or + * <code>null</code> if no such user can be found + */ + DirectoryUser findUserById(Guid id); + + /** + * Retrieves a set of users from the directory given their identifiers. + * + * @param ids the set of identifiers + * @return a set containing an user for each identifier in the given set + * with no particular order, note that the returned set may contain less + * elements than the given set of identifiers and that it may be in a + * different order + */ + Set<DirectoryUser> findUsersById(Set<Guid> ids); + + /** + * Retrieves a group from the directory given its identifier. Note that this + * identifier is the one assigned by the engine to the group, not the one + * used directly by the directory itself. It is the responsibility of the + * broker to translate this identifier into whatever the actual directory + * needs. + * + * @param id the identifier of the group + * @return the group corresponding to the given identifier or + * <code>null</code> if no such group can be found + */ + DirectoryGroup findGroupById(Guid id); + + /** + * Search the directory looking for users that match the given search query. + * + * @param query the query + * @return a list containing the users that match the given query + */ + Set<DirectoryUser> findUsersByQuery(String query); + + /** + * Search the directory looking for groups that match the given search + * query. + * + * @param query the query + * @return a list containing the groups that match the given query + */ + Set<DirectoryGroup> findGroupsByQuery(String query); +} diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryEntry.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryEntry.java new file mode 100644 index 0000000..6fb51b8 --- /dev/null +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryEntry.java @@ -0,0 +1,109 @@ +package org.ovirt.engine.core.common.users; + +import org.ovirt.engine.core.common.businessentities.IVdcQueryable; +import org.ovirt.engine.core.common.utils.ObjectUtils; +import org.ovirt.engine.core.compat.Guid; + +public class DirectoryEntry extends IVdcQueryable { + // Serialization id: + private static final long serialVersionUID = -5689096270467866486L; + + // Reference to the directory where this entry was originated: + private Directory directory; + + // The attributes of the entry: + private Guid id = new Guid(); + private String name; + private DirectoryEntryStatus status = DirectoryEntryStatus.INACTIVE; + + public DirectoryEntry(Directory directory, Guid id, String name) { + this.directory = directory; + this.id = id; + this.name = name; + } + + public Guid getId() { + return id; + } + + public void setId(Guid id) { + this.id = id; + } + + public Directory getDirectory() { + return directory; + } + + public void setDirectory(Directory directory) { + this.directory = directory; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public DirectoryEntryStatus getStatus() { + return status; + } + + public void setStatus(DirectoryEntryStatus status) { + this.status = status; + } + + @Override + public Object getQueryableId() { + return id; + } + + /** + * Return the FQN of a user in a form of user@domain. If the domain is + * empty then only return the user name. + */ + public String getFQN() { + // Empty user name or a user with empty domain will be returned as is: + if (name == null || name.length() == 0 || name.contains("@") || directory == null) { + return name; + } else { + return name + "@" + directory.getName(); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (id == null? 0: id.hashCode()); + result = prime * result + (name == null? 0: name.hashCode()); + result = prime * result + (status == null? 0: status.hashCode()); + result = prime * result + (directory == null? 0: directory.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + DirectoryEntry other = (DirectoryEntry) obj; + return + ObjectUtils.objectsEqual(id, other.id) && + ObjectUtils.objectsEqual(name, other.name) && + ObjectUtils.objectsEqual(status, other.status) && + ObjectUtils.objectsEqual(directory, other.directory) + ; + } + + public String toString() { + return name + "@" + directory.getName(); + } +} diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryEntryStatus.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryEntryStatus.java new file mode 100644 index 0000000..64b7baf --- /dev/null +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryEntryStatus.java @@ -0,0 +1,38 @@ +package org.ovirt.engine.core.common.users; + +import java.util.HashMap; +import java.util.Map; + +import org.ovirt.engine.core.common.businessentities.Identifiable; + +/** + * A directory entry is active if it was found in the directory during the last + * check performed by the engine. + */ +public enum DirectoryEntryStatus implements Identifiable { + INACTIVE(0), + ACTIVE(1); + + private int value; + + private static Map<Integer, DirectoryEntryStatus> mappings = new HashMap<Integer, DirectoryEntryStatus>(); + + static { + for (DirectoryEntryStatus status : values()) { + mappings.put(status.getValue(), status); + } + } + + private DirectoryEntryStatus(int value) { + this.value = value; + } + + @Override + public int getValue() { + return value; + } + + public static DirectoryEntryStatus forValue(int value) { + return mappings.get(value); + } +} diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryGroup.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryGroup.java new file mode 100644 index 0000000..f675bfc --- /dev/null +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryGroup.java @@ -0,0 +1,12 @@ +package org.ovirt.engine.core.common.users; + +import org.ovirt.engine.core.compat.Guid; + +public class DirectoryGroup extends DirectoryEntry { + // Serialization identifier: + private static final long serialVersionUID = 7446478647138904658L; + + public DirectoryGroup(Directory directory, Guid id, String name) { + super(directory, id, name); + } +} diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryUser.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryUser.java new file mode 100644 index 0000000..fd71a89 --- /dev/null +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/users/DirectoryUser.java @@ -0,0 +1,136 @@ +package org.ovirt.engine.core.common.users; + +import java.util.ArrayList; +import java.util.List; + +import org.ovirt.engine.core.common.utils.ObjectUtils; +import org.ovirt.engine.core.compat.Guid; + +public class DirectoryUser extends DirectoryEntry { + // Serialization id: + private static final long serialVersionUID = -5689096270467866486L; + + // The attributes of the user, as extracted from the underlying directory: + private String password; + private String firstName; + private String lastName; + private String title; + private String email; + private String department; + + // Flag indicating if this user has the administrator role: + private boolean isAdmin = false; + + // The list of groups this user belongs to: + private List<DirectoryGroup> groups = new ArrayList<DirectoryGroup>(0); + + public DirectoryUser(Directory directory, Guid id, String name) { + super(directory, id, name); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public boolean isAdmin() { + return isAdmin; + } + + public void setAdmin(boolean isAdmin) { + this.isAdmin = isAdmin; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + /** + * Returns the list of groups that this user belongs to. Note that the list + * returned may be unmodifiable, so don't try to alter it in any way. + */ + public List<DirectoryGroup> getGroups() { + return groups; + } + + public void setGroups(List<DirectoryGroup> groups) { + this.groups = groups; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (password == null? 0: password.hashCode()); + result = prime * result + (firstName == null? 0: firstName.hashCode()); + result = prime * result + (lastName == null? 0: lastName.hashCode()); + result = prime * result + (title == null? 0: title.hashCode()); + result = prime * result + (email == null? 0: email.hashCode()); + result = prime * result + (department == null? 0: department.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + if (!super.equals(obj)) { + return false; + } + DirectoryUser other = (DirectoryUser) obj; + return + ObjectUtils.objectsEqual(password, other.password) && + ObjectUtils.objectsEqual(department, other.department) && + ObjectUtils.objectsEqual(firstName, other.firstName) && + ObjectUtils.objectsEqual(lastName, other.lastName) && + ObjectUtils.objectsEqual(email, other.email) && + ObjectUtils.objectsEqual(department, other.department) + ; + } +} -- To view, visit http://gerrit.ovirt.org/15596 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If84a0c9d6553d81cdbbe224972696f169cca90d4 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Juan Hernandez <juan.hernan...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches