/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the License at the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apereo.portal.user;
import java.io.Serializable;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apereo.portal.IUserProfile;
import org.apereo.portal.PortalException;
import org.apereo.portal.UserInstance;
import org.apereo.portal.UserPreferencesManager;
import org.apereo.portal.i18n.ILocaleStore;
import org.apereo.portal.i18n.LocaleManager;
import org.apereo.portal.layout.IUserLayoutManager;
import org.apereo.portal.layout.IUserLayoutStore;
import org.apereo.portal.layout.UserLayoutManagerFactory;
import org.apereo.portal.layout.profile.IProfileMapper;
import org.apereo.portal.security.IPerson;
import org.apereo.portal.security.IPersonManager;
import org.apereo.portal.security.PortalSecurityException;
import org.apereo.portal.url.IPortalRequestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Determines which user instance object to use for a given user.
*/
@Service("userInstanceManager")
public class UserInstanceManagerImpl implements IUserInstanceManager {
private static final String KEY = UserInstanceManagerImpl.class.getName() + ".USER_INSTANCE";
protected final Log logger = LogFactory.getLog(UserInstanceManagerImpl.class);
private ILocaleStore localeStore;
private IUserLayoutStore userLayoutStore;
private IPersonManager personManager;
private IPortalRequestUtils portalRequestUtils;
private IProfileMapper profileMapper;
private UserLayoutManagerFactory userLayoutManagerFactory;
@Autowired
public void setUserLayoutManagerFactory(UserLayoutManagerFactory userLayoutManagerFactory) {
this.userLayoutManagerFactory = userLayoutManagerFactory;
}
@Autowired
public void setLocaleStore(ILocaleStore localeStore) {
this.localeStore = localeStore;
}
@Autowired
public void setUserLayoutStore(IUserLayoutStore userLayoutStore) {
this.userLayoutStore = userLayoutStore;
}
@Autowired
public void setPersonManager(IPersonManager personManager) {
this.personManager = personManager;
}
@Autowired
public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) {
this.portalRequestUtils = portalRequestUtils;
}
@Autowired
public void setProfileMapper(IProfileMapper profileMapper) {
this.profileMapper = profileMapper;
}
/**
* Returns the UserInstance object that is associated with the given request.
*
* @param request Incoming HttpServletRequest
* @return UserInstance object associated with the given request
*/
@Override
public IUserInstance getUserInstance(HttpServletRequest request) throws PortalException {
try {
request = this.portalRequestUtils.getOriginalPortalRequest(request);
} catch (IllegalArgumentException iae) {
//ignore, just means that this isn't a wrapped request
}
// Use request attributes first for the fastest possible retrieval
IUserInstance userInstance = (IUserInstance) request.getAttribute(KEY);
if (userInstance != null) {
return userInstance;
}
final IPerson person;
try {
// Retrieve the person object that is associated with the request
person = this.personManager.getPerson(request);
} catch (Exception e) {
logger.error("Exception while retrieving IPerson!", e);
throw new PortalSecurityException("Could not retrieve IPerson", e);
}
if (person == null) {
throw new PortalSecurityException(
"PersonManager returned null person for this request. With no user, there's no UserInstance. Is PersonManager misconfigured? RDBMS access misconfigured?");
}
final HttpSession session = request.getSession();
if (session == null) {
throw new IllegalStateException(
"HttpServletRequest.getSession() returned a null session for request: "
+ request);
}
// Return the UserInstance object if it's in the session
UserInstanceHolder userInstanceHolder = getUserInstanceHolder(session);
if (userInstanceHolder != null) {
userInstance = userInstanceHolder.getUserInstance();
if (userInstance != null) {
return userInstance;
}
}
// Create either a UserInstance or a GuestUserInstance
final LocaleManager localeManager = this.getLocaleManager(request, person);
final String userAgent = this.getUserAgent(request);
final IUserProfile userProfile =
this.getUserProfile(request, person, localeManager, userAgent);
//Create the user layout manager and user instance object
IUserLayoutManager userLayoutManager =
userLayoutManagerFactory.getUserLayoutManager(person, userProfile);
final UserPreferencesManager userPreferencesManager =
new UserPreferencesManager(person, userProfile, userLayoutManager);
userInstance = new UserInstance(person, userPreferencesManager, localeManager);
//Ensure the newly created UserInstance is cached in the session
if (userInstanceHolder == null) {
userInstanceHolder = new UserInstanceHolder();
}
userInstanceHolder.setUserInstance(userInstance);
session.setAttribute(KEY, userInstanceHolder);
request.setAttribute(KEY, userInstance);
// Return the new UserInstance
return userInstance;
}
protected IUserProfile getUserProfile(
HttpServletRequest request,
IPerson person,
LocaleManager localeManager,
String userAgent) {
final String profileFname = profileMapper.getProfileFname(person, request);
IUserProfile userProfile = userLayoutStore.getUserProfileByFname(person, profileFname);
if (userProfile == null) {
userProfile = userLayoutStore.getSystemProfileByFname(profileFname);
}
if (localeManager != null && LocaleManager.isLocaleAware()) {
userProfile.setLocaleManager(localeManager);
}
return userProfile;
}
protected LocaleManager getLocaleManager(HttpServletRequest request, IPerson person) {
final String acceptLanguage = request.getHeader("Accept-Language");
final Locale[] userLocales = localeStore.getUserLocales(person);
return new LocaleManager(person, userLocales, acceptLanguage);
}
protected String getUserAgent(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent");
if (StringUtils.isEmpty(userAgent)) {
userAgent = "null";
}
return userAgent;
}
protected UserInstanceHolder getUserInstanceHolder(final HttpSession session) {
return (UserInstanceHolder) session.getAttribute(KEY);
}
/**
* Serializable wrapper class so the UserInstance object can be indirectly stored in the
* session. The manager can deal with this class returning a null value and its field is
* transient so the session can be serialized successfully with the UserInstance object in it.
*
* <p>Implements HttpSessionBindingListener and delegates those methods to the wrapped
* UserInstance, if present.
*/
private static class UserInstanceHolder implements Serializable {
private static final long serialVersionUID = 1L;
private transient IUserInstance ui = null;
/** @return Returns the userInstance. */
protected IUserInstance getUserInstance() {
return this.ui;
}
/** @param userInstance The userInstance to set. */
protected void setUserInstance(IUserInstance userInstance) {
this.ui = userInstance;
}
}
}