From 5bf6afd10ebff58db833509a514ade1c55a59039 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 5 Nov 2010 19:47:52 +0100 Subject: [PATCH] added BasicUserManager and XmlUserHandler --- .../java/sonia/scm/user/BasicUserManager.java | 419 ++++++++++++++++++ .../user/UserHandlerNotFoundException.java | 58 +++ .../main/java/sonia/scm/user/UserManager.java | 4 +- .../java/sonia/scm/user/XmlUserHandler.java | 358 +++++++++++++++ .../src/main/java/sonia/scm/util/IOUtil.java | 17 + .../resources/scm/config/admin-account.xml | 8 + 6 files changed, 863 insertions(+), 1 deletion(-) create mode 100644 scm-core/src/main/java/sonia/scm/user/BasicUserManager.java create mode 100644 scm-core/src/main/java/sonia/scm/user/UserHandlerNotFoundException.java create mode 100644 scm-core/src/main/java/sonia/scm/user/XmlUserHandler.java create mode 100644 scm-core/src/main/resources/scm/config/admin-account.xml diff --git a/scm-core/src/main/java/sonia/scm/user/BasicUserManager.java b/scm-core/src/main/java/sonia/scm/user/BasicUserManager.java new file mode 100644 index 0000000000..5b8f722263 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/user/BasicUserManager.java @@ -0,0 +1,419 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.user; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.ConfigurationException; +import sonia.scm.HandlerEvent; +import sonia.scm.SCMContextProvider; +import sonia.scm.Type; +import sonia.scm.util.AssertUtil; +import sonia.scm.util.IOUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +public class BasicUserManager implements UserManager +{ + + /** the logger for BasicUserManager */ + private static final Logger logger = + LoggerFactory.getLogger(BasicUserManager.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param handlerSet + */ + @Inject + public BasicUserManager(Set handlerSet) + { + AssertUtil.assertIsNotEmpty(handlerSet); + + for (UserHandler handler : handlerSet) + { + addHandler(handler); + } + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param listener + */ + @Override + public void addListener(UserListener listener) + { + listenerSet.add(listener); + } + + /** + * Method description + * + * + * @throws IOException + */ + @Override + public void close() throws IOException + { + for (UserHandler handler : handlerMap.values()) + { + IOUtil.close(handler); + } + } + + /** + * Method description + * + * + * @param user + * + * @throws Exception + * @throws IOException + */ + @Override + public void create(User user) throws Exception, IOException + { + if (logger.isInfoEnabled()) + { + logger.info("create user {} of type {}", user.getName(), user.getType()); + } + + getHandler(user).create(user); + fireEvent(user, HandlerEvent.CREATE); + } + + /** + * Method description + * + * + * @param user + * + * @throws Exception + * @throws IOException + */ + @Override + public void delete(User user) throws Exception, IOException + { + if (logger.isInfoEnabled()) + { + logger.info("create user {} of type {}", user.getName(), user.getType()); + } + + getHandler(user).delete(user); + fireEvent(user, HandlerEvent.DELETE); + } + + /** + * Method description + * + * + * @param context + */ + @Override + public void init(SCMContextProvider context) + { + for (UserHandler handler : handlerMap.values()) + { + handler.init(context); + } + } + + /** + * Method description + * + * + * @param user + * + * @throws Exception + * @throws IOException + */ + @Override + public void modify(User user) throws Exception, IOException + { + if (logger.isInfoEnabled()) + { + logger.info("modify user {} of type {}", user.getName(), user.getType()); + } + + getHandler(user).modify(user); + fireEvent(user, HandlerEvent.MODIFY); + } + + /** + * Method description + * + * + * @param user + * + * @throws Exception + * @throws IOException + */ + @Override + public void refresh(User user) throws Exception, IOException + { + if (logger.isInfoEnabled()) + { + logger.info("refresh user {} of type {}", user.getName(), user.getType()); + } + + getHandler(user).refresh(user); + } + + /** + * Method description + * + * + * @param listener + */ + @Override + public void removeListener(UserListener listener) + { + listenerSet.remove(listener); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param id + * + * @return + */ + @Override + public User get(String id) + { + User user = null; + + for (UserHandler handler : handlerMap.values()) + { + if (handler.isConfigured()) + { + user = handler.get(id); + + if (user != null) + { + break; + } + } + } + + return user; + } + + /** + * Method description + * + * + * @return + */ + @Override + public Collection getAll() + { + if (logger.isDebugEnabled()) + { + logger.debug("fetch all users"); + } + + Set repositories = new HashSet(); + + for (UserHandler handler : handlerMap.values()) + { + if (handler.isConfigured()) + { + Collection handlerRepositories = handler.getAll(); + + if (handlerRepositories != null) + { + repositories.addAll(handlerRepositories); + } + } + } + + if (logger.isDebugEnabled()) + { + logger.debug("fetched {} users", repositories.size()); + } + + return repositories; + } + + /** + * Method description + * + * + * @param type + * + * @return + */ + @Override + public UserHandler getHandler(String type) + { + return handlerMap.get(type); + } + + /** + * Method description + * + * + * @return + */ + @Override + public Collection getTypes() + { + return typeSet; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param handler + */ + private void addHandler(UserHandler handler) + { + AssertUtil.assertIsNotNull(handler); + + Type type = handler.getType(); + + AssertUtil.assertIsNotNull(type); + + if (handlerMap.containsKey(type.getName())) + { + throw new ConfigurationException( + type.getName().concat("allready registered")); + } + + if (logger.isInfoEnabled()) + { + logger.info("added UserHandler {} for type {}", handler.getClass(), type); + } + + handlerMap.put(type.getName(), handler); + typeSet.add(type); + } + + /** + * Method description + * + * + * @param user + * @param event + */ + private void fireEvent(User user, HandlerEvent event) + { + for (UserListener listener : listenerSet) + { + listener.onEvent(user, event); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param user + * + * @return + * + * @throws UserException + */ + private UserHandler getHandler(User user) throws UserException + { + AssertUtil.assertIsNotNull(user); + + String type = user.getType(); + + AssertUtil.assertIsNotEmpty(type); + + UserHandler handler = handlerMap.get(type); + + if (handler == null) + { + throw new UserHandlerNotFoundException( + "could not find UserHandler for ".concat(type)); + } + else if (!handler.isConfigured()) + { + throw new UserException( + "UserHandler for type ".concat(type).concat(" is not configured")); + } + + return handler; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private Set listenerSet = new HashSet(); + + /** Field description */ + private Map handlerMap = new HashMap(); + + /** Field description */ + private Set typeSet = new LinkedHashSet(); +} diff --git a/scm-core/src/main/java/sonia/scm/user/UserHandlerNotFoundException.java b/scm-core/src/main/java/sonia/scm/user/UserHandlerNotFoundException.java new file mode 100644 index 0000000000..f4348a9444 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/user/UserHandlerNotFoundException.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.user; + +/** + * + * @author Sebastian Sdorra + */ +public class UserHandlerNotFoundException extends UserException +{ + + /** Field description */ + private static final long serialVersionUID = -4704703054646330523L; + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param message + */ + public UserHandlerNotFoundException(String message) + { + super(message); + } +} diff --git a/scm-core/src/main/java/sonia/scm/user/UserManager.java b/scm-core/src/main/java/sonia/scm/user/UserManager.java index d71e65f2bb..959d2272f4 100644 --- a/scm-core/src/main/java/sonia/scm/user/UserManager.java +++ b/scm-core/src/main/java/sonia/scm/user/UserManager.java @@ -35,13 +35,15 @@ package sonia.scm.user; //~--- non-JDK imports -------------------------------------------------------- +import sonia.scm.ListenerSupport; import sonia.scm.Manager; /** * * @author Sebastian Sdorra */ -public interface UserManager extends Manager +public interface UserManager + extends Manager, ListenerSupport { /** diff --git a/scm-core/src/main/java/sonia/scm/user/XmlUserHandler.java b/scm-core/src/main/java/sonia/scm/user/XmlUserHandler.java new file mode 100644 index 0000000000..9bd10122b5 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/user/XmlUserHandler.java @@ -0,0 +1,358 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.user; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.inject.Singleton; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.SCMContextProvider; +import sonia.scm.Type; +import sonia.scm.util.IOUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.xml.bind.JAXB; + +/** + * + * @author Sebastian Sdorra + */ +@Singleton +public class XmlUserHandler implements UserHandler +{ + + /** Field description */ + public static final String ADMIN_FILE = "scmadmin.xml"; + + /** Field description */ + public static final String ADMIN_PATH = "sonia/scm/admin-account.xml"; + + /** Field description */ + public static final String FILE_EXTENSION = ".xml"; + + /** Field description */ + public static final String TYPE_DISPLAYNAME = "XML"; + + /** Field description */ + public static final String TYPE_NAME = "xml"; + + /** Field description */ + public static final Type type = new Type(TYPE_NAME, TYPE_DISPLAYNAME); + + /** Field description */ + public static final String DIRECTORY = + "user".concat(File.separator).concat("xml"); + + /** the logger for XmlUserHandler */ + private static final Logger logger = + LoggerFactory.getLogger(XmlUserHandler.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @throws IOException + */ + @Override + public void close() throws IOException + { + + // do nothing + } + + /** + * Method description + * + * + * @param user + * + * @throws IOException + * @throws UserException + */ + @Override + public void create(User user) throws UserException, IOException + { + File file = getFile(user.getName()); + + if (file.exists()) + { + throw new UserAllreadyExistException(); + } + + JAXB.marshal(User.class, file); + } + + /** + * Method description + * + * + * @param user + * + * @throws IOException + * @throws UserException + */ + @Override + public void delete(User user) throws UserException, IOException + { + File file = getFile(user.getName()); + + if (file.exists()) + { + IOUtil.delete(file); + } + else + { + throw new UserException("user does not exists"); + } + } + + /** + * Method description + * + * + * @param context + */ + @Override + public void init(SCMContextProvider context) + { + File directory = context.getBaseDirectory(); + + userDirectory = new File(directory, DIRECTORY); + + if (!userDirectory.exists()) + { + IOUtil.mkdirs(userDirectory); + createAdminAccount(); + } + } + + /** + * Method description + * + * + * @param user + * + * @throws IOException + * @throws UserException + */ + @Override + public void modify(User user) throws UserException, IOException + { + File file = getFile(user.getName()); + + if (file.exists()) + { + JAXB.marshal(user, file); + } + else + { + throw new UserException("user does not exists"); + } + } + + /** + * Method description + * + * + * @param user + * + * @throws IOException + * @throws UserException + */ + @Override + public void refresh(User user) throws UserException, IOException + { + User fresh = get(user.getName()); + + if (fresh == null) + { + throw new UserException("user does not exists"); + } + + user.setDisplayName(fresh.getDisplayName()); + user.setMail(fresh.getMail()); + user.setPassword(fresh.getPassword()); + user.setType(TYPE_NAME); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param id + * + * @return + */ + @Override + public User get(String id) + { + User user = null; + File file = getFile(id); + + if (file.exists()) + { + user = JAXB.unmarshal(file, User.class); + } + + return user; + } + + /** + * Method description + * + * + * @return + */ + @Override + public Collection getAll() + { + List users = new ArrayList(); + File[] userFiles = userDirectory.listFiles(new FilenameFilter() + { + @Override + public boolean accept(File dir, String name) + { + return name.endsWith(FILE_EXTENSION); + } + }); + + for (File userFile : userFiles) + { + try + { + User user = JAXB.unmarshal(userFile, User.class); + + if (user != null) + { + users.add(user); + } + } + catch (Exception ex) + { + logger.error(ex.getMessage(), ex); + } + } + + return users; + } + + /** + * Method description + * + * + * @return + */ + @Override + public Type getType() + { + return type; + } + + /** + * Method description + * + * + * @return + */ + @Override + public boolean isConfigured() + { + return (userDirectory != null) && userDirectory.exists(); + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + */ + private void createAdminAccount() + { + InputStream input = XmlUserHandler.class.getResourceAsStream(TYPE_NAME); + FileOutputStream output = null; + + try + { + output = new FileOutputStream(new File(userDirectory, ADMIN_FILE)); + IOUtil.copy(input, output); + } + catch (IOException ex) + { + logger.error("could not create AdminAccount", ex); + } + finally + { + IOUtil.close(input); + IOUtil.close(output); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param id + * + * @return + */ + private File getFile(String id) + { + return new File(userDirectory, id.concat(FILE_EXTENSION)); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private File userDirectory; +} diff --git a/scm-core/src/main/java/sonia/scm/util/IOUtil.java b/scm-core/src/main/java/sonia/scm/util/IOUtil.java index 60efe89d1a..62ed1d88fd 100644 --- a/scm-core/src/main/java/sonia/scm/util/IOUtil.java +++ b/scm-core/src/main/java/sonia/scm/util/IOUtil.java @@ -29,6 +29,8 @@ * */ + + package sonia.scm.util; //~--- non-JDK imports -------------------------------------------------------- @@ -159,6 +161,21 @@ public class IOUtil } } + /** + * Method description + * + * + * @param directory + */ + public static void mkdirs(File directory) + { + if (!directory.exists() &&!directory.mkdirs()) + { + throw new IllegalStateException( + "could not create directory ".concat(directory.getPath())); + } + } + //~--- inner classes -------------------------------------------------------- /** diff --git a/scm-core/src/main/resources/scm/config/admin-account.xml b/scm-core/src/main/resources/scm/config/admin-account.xml new file mode 100644 index 0000000000..f66a6bda0c --- /dev/null +++ b/scm-core/src/main/resources/scm/config/admin-account.xml @@ -0,0 +1,8 @@ + + + scmadmin + SCM Administrator + scm-admin@scm-manager.com + ff8f5c593a01f9fcd3ed48b09a4b013e8d8f3be7 + xml +