/******************************************************************************* * Copyright (c) 2010-2014 SAP AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * SAP AG - initial API and implementation *******************************************************************************/ package org.eclipse.skalli.services.user; import java.text.MessageFormat; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.eclipse.skalli.model.User; import org.eclipse.skalli.services.BundleProperties; import org.eclipse.skalli.services.configuration.Configurations; import org.osgi.service.component.ComponentConstants; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility class that provides methods for retrieving the currently active * {@link UserService user service} and some frequently used utility * functions for looking up users. */ public class UserServices { private static final Logger LOG = LoggerFactory.getLogger(UserServices.class); private static final String LOCAL_USERSTORE = "local"; //$NON-NLS-1$ private static final String CONFIG_KEY_USERSTORE = "userStore"; //$NON-NLS-1$ private static final String USERSTORE_TYPE_PROPERTY = CONFIG_KEY_USERSTORE + ".type"; //$NON-NLS-1$ private static final String USERSTORE_USE_LOCAL_FALLBACK_PROPERTY = CONFIG_KEY_USERSTORE + ".useLocalFallback"; //$NON-NLS-1$ private static Map<String, UserService> byType = new ConcurrentHashMap<String, UserService>(); private static volatile UserService activeUserService; protected void activate(ComponentContext context) { activeUserService = null; LOG.info(MessageFormat.format("[UserServices] {0} : activated", (String) context.getProperties().get(ComponentConstants.COMPONENT_NAME))); } protected void deactivate(ComponentContext context) { activeUserService = null; LOG.info(MessageFormat.format("[UserServices] {0} : deactivated", (String) context.getProperties().get(ComponentConstants.COMPONENT_NAME))); } protected void bindUserService(UserService userService) { String type = userService.getType(); if (StringUtils.isNotBlank(type)) { byType.put(type, userService); activeUserService = null; LOG.info(MessageFormat.format("[UserServices(type={0})][registered {1}]", type, userService)); } } protected void unbindUserService(UserService userService) { String type = userService.getType(); if (StringUtils.isNotBlank(type)) { byType.remove(type); activeUserService = null; LOG.info(MessageFormat.format("[UserServices(type={0})][unregistered {1}]", type, userService)); } } /** * Returns the currently active {@link UserService}. * <p> * Checks whether a dedicated user service has been {@link ConfigKeyUserStore configured}, * otherwise falls backs to {@LocalUserStore}, if the configuration permits that. * * @return the configured and active user service, or <code>null</code> if * no user service is registered and fallback to the local user store is forbidden. */ public static UserService getUserService() { UserService userService = activeUserService; if (userService == null) { synchronized (UserServices.class) { userService = activeUserService; if (userService == null) { activeUserService = userService = getActiveUserService(); } } } return userService; } private static UserService getActiveUserService() { UserService userService = null; // retrieve params from configuration properties; // use "local" userstore as fallback in case no explicit property/configuration is available String type = BundleProperties.getProperty(USERSTORE_TYPE_PROPERTY, LOCAL_USERSTORE); boolean useLocalFallback = BooleanUtils.toBoolean( BundleProperties.getProperty(USERSTORE_USE_LOCAL_FALLBACK_PROPERTY)); // if there is a configuration via REST API available, override the properties UserStoreConfig userStoreConfig = Configurations.getConfiguration(UserStoreConfig.class); if (userStoreConfig != null) { type = userStoreConfig.getType(); useLocalFallback = userStoreConfig.isUseLocalFallback(); } // first: lookup the preferred user store if (StringUtils.isNotBlank(type)) { userService = byType.get(type); } // second: if the preferred user store is not available, but fallback // to the local store is allowed, use the local store if (userService == null && useLocalFallback) { LOG.info(MessageFormat.format( "Preferred user service ''{0}'' not found, falling back to local user store", type)); userService = byType.get(LOCAL_USERSTORE); } return userService; } /** * Returns the {@link User} matching a given unique identifier. * <p> * This is a convenience method equivalent to obtaining the active user service * with {@link #getUserService()} followed by {@link UserService#getUserById(String)}. * * @param userId the unique identifier of the user. * * @return a user, which may be the {@link User#isUnknown() unknown} user, * if the given unique identifier does not match any user or no user store is active. * returns <code>null</code>, if the given <code>userId</code> is <code>null</code> * or a blank string. */ public static User getUser(String userId) { User user = null; if (StringUtils.isNotBlank(userId)) { UserService userService = getUserService(); user = userService != null? userService.getUserById(userId) : new User(userId); } return user; } }