gt: 		if (remoteUser == null) {
context: package fr.univmobile.backend;
  
  import static com.google.common.base.Preconditions.checkNotNull;
  import static fr.univmobile.backend.core.impl.ConnectionType.MYSQL;
  import static org.apache.commons.lang3.CharEncoding.UTF_8;
  import static org.apache.commons.lang3.StringUtils.isBlank;
  import static org.apache.commons.lang3.StringUtils.split;
  import static org.apache.commons.lang3.StringUtils.substringAfter;
  import static org.apache.commons.lang3.StringUtils.substringBefore;
  import static org.apache.commons.lang3.StringUtils.substringBeforeLast;
  
  import java.io.File;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.PrintWriter;
  import java.sql.Connection;
  import java.sql.SQLException;
  import java.util.Enumeration;
  
  import javax.annotation.Nullable;
  import javax.naming.InitialContext;
  import javax.naming.NamingException;
  import javax.servlet.ServletException;
  import javax.servlet.ServletOutputStream;
  import javax.servlet.UnavailableException;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.sql.DataSource;
  
  import org.apache.commons.io.IOUtils;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  import fr.univmobile.backend.client.AbstractClientFromLocal;
  import fr.univmobile.backend.client.CommentClient;
  import fr.univmobile.backend.client.CommentClientFromLocal;
  import fr.univmobile.backend.client.PoiClient;
  import fr.univmobile.backend.client.PoiClientFromLocal;
  import fr.univmobile.backend.client.RegionClient;
  import fr.univmobile.backend.client.RegionClientFromLocal;
  import fr.univmobile.backend.client.SessionClient;
  import fr.univmobile.backend.client.SessionClientFromLocal;
  import fr.univmobile.backend.client.json.CommentJSONClient;
  import fr.univmobile.backend.client.json.CommentJSONClientImpl;
  import fr.univmobile.backend.client.json.PoiJSONClient;
  import fr.univmobile.backend.client.json.PoiJSONClientImpl;
  import fr.univmobile.backend.client.json.RegionJSONClient;
  import fr.univmobile.backend.client.json.RegionJSONClientImpl;
  import fr.univmobile.backend.client.json.SessionJSONClient;
  import fr.univmobile.backend.client.json.SessionJSONClientImpl;
  import fr.univmobile.backend.core.CommentDataSource;
  import fr.univmobile.backend.core.CommentManager;
  //import fr.univmobile.backend.core.CommentThreadDataSource;
  import fr.univmobile.backend.core.PoiDataSource;
  import fr.univmobile.backend.core.PoiTreeDataSource;
  import fr.univmobile.backend.core.RegionDataSource;
  import fr.univmobile.backend.core.SearchManager;
  import fr.univmobile.backend.core.SessionManager;
  import fr.univmobile.backend.core.UploadManager;
  import fr.univmobile.backend.core.UploadNotFoundException;
  import fr.univmobile.backend.core.User;
  import fr.univmobile.backend.core.UserDataSource;
  import fr.univmobile.backend.core.impl.CommentManagerImpl;
  import fr.univmobile.backend.core.impl.LogQueueDbImpl;
  import fr.univmobile.backend.core.impl.SearchManagerImpl;
  import fr.univmobile.backend.core.impl.SessionManagerImpl;
  import fr.univmobile.backend.core.impl.UploadManagerImpl;
  import fr.univmobile.backend.history.LogQueue;
  import fr.univmobile.backend.json.AbstractJSONController;
  import fr.univmobile.backend.json.CommentsJSONController;
  import fr.univmobile.backend.json.EndpointsJSONController;
  import fr.univmobile.backend.json.JsonHtmler;
  import fr.univmobile.backend.json.PoisJSONController;
  import fr.univmobile.backend.json.RegionsJSONController;
  import fr.univmobile.backend.json.SessionJSONController;
  import fr.univmobile.backend.json.UniversitiesJSONController;
  import fr.univmobile.backend.twitter.ApplicationOnly;
  import fr.univmobile.backend.twitter.TwitterAccess;
  import fr.univmobile.commons.datasource.impl.BackendDataSourceFileSystem;
  import fr.univmobile.commons.tx.TransactionManager;
  import fr.univmobile.web.commons.AbstractUnivMobileServlet;
  import fr.univmobile.web.commons.BuildInfoUtils;
  import fr.univmobile.web.commons.PageNotFoundException;
  import fr.univmobile.web.commons.UnivMobileHttpUtils;
  
  public final class BackendServlet extends AbstractUnivMobileServlet {
  
  	/**
  	 * for serialization.
  	 */
  	private static final long serialVersionUID = -4796360020211862333L;
  
  	private UserDataSource users;
  	private RegionDataSource regions;
  	private PoiDataSource pois;
  	// private PoiTreeDataSource poiTrees;
  	private UploadManager uploadManager;
  
  	private AbstractJSONController[] jsonControllers;
  
  	@Nullable
  	private String[] optional_jsonBaseURLs;
  
  	@Override
  	public void init() throws ServletException {
  
  		if (log.isInfoEnabled()) {
  			log.info(this + ": init()...");
  		}
  
  		// 0. SERVLET INIT PARAMETERS
  
  		final String dataDir = getServletConfig().getInitParameter("dataDir");
  
  		if (isBlank(dataDir)) {
  			throw new UnavailableException("Cannot find init-param: dataDir");
  		}
  
  		final String optional_jsonBaseURLs = getServletConfig()
  				.getInitParameter("optional-jsonBaseURLs");
  
  		if (isBlank(optional_jsonBaseURLs)) {
  
  			this.optional_jsonBaseURLs = null;
  
  		} else {
  
  			this.optional_jsonBaseURLs = //
  			split(optional_jsonBaseURLs.replace(',', ' '));
  
  			for (int i = 0; i < this.optional_jsonBaseURLs.length; ++i) {
  
  				final String optional_jsonBaseURL = this.optional_jsonBaseURLs[i];
  
  				if (optional_jsonBaseURL.endsWith("/json/")) {
  
  					this.optional_jsonBaseURLs[i] = substringBeforeLast(
  							optional_jsonBaseURL, "json/");
  
  				} else if (optional_jsonBaseURL.endsWith("/json")) {
  
  					this.optional_jsonBaseURLs[i] = substringBeforeLast(
  							optional_jsonBaseURL, "json");
  
  				} else {
  
  					throw new UnavailableException(
  							"optional-jsonBaseURL should end with \"/json/\" or \"/json\": "
  									+ optional_jsonBaseURL);
  				}
  			}
  		}
  
  		// 1. TTRANSACTION MANAGER + DATA
  
  		final TransactionManager tx = TransactionManager.getInstance();
  
  		final File usersDir = new File(dataDir, "users");
  		final File regionsDir = new File(dataDir, "regions");
  		final File poisDir = new File(dataDir, "pois");
  		final File poiTreesDir = new File(dataDir, "poitrees");
  		final File uploadsDir = new File(dataDir, "uploads");
  		final File commentsDir = new File(dataDir, "comments");
  
  		// 2. DATASOURCES AND CLIENTS
  
  		final PoiTreeDataSource poiTrees;
  		final CommentDataSource comments;
  		final CommentManager commentManager;
  		final SearchManager searchManager;
  		final SessionManager sessionManager;
  		final DataSource ds;
  
  		try {
  
  			users = BackendDataSourceFileSystem.newDataSource(
  					UserDataSource.class, usersDir);
  
  			regions = BackendDataSourceFileSystem.newDataSource(
  					RegionDataSource.class, regionsDir);
  
  			poiTrees = BackendDataSourceFileSystem.newDataSource(
  					PoiTreeDataSource.class, poiTreesDir);
  
  			poiTrees.getByUid("ile_de_france"); // check for "poitree"
  
  			pois = BackendDataSourceFileSystem.newDataSource(
  					PoiDataSource.class, poisDir);
  
  			uploadManager = new UploadManagerImpl(uploadsDir);
  
  			comments = BackendDataSourceFileSystem.newDataSource(
  					CommentDataSource.class, commentsDir);
  
  			final InitialContext context = new InitialContext();
  
  			ds = (DataSource) context.lookup("java:/comp/env/jdbc/univmobile");
  
  			checkDataSource(ds);
  
  			final LogQueue logQueue = new LogQueueDbImpl(MYSQL, ds);
  
  			searchManager = new SearchManagerImpl(logQueue, MYSQL, ds);
  
  			commentManager = new CommentManagerImpl(logQueue, comments,
  					searchManager, MYSQL, ds);
  
  			sessionManager = new SessionManagerImpl(logQueue, users, MYSQL, ds);
  
  		} catch (final NamingException e) {
  			throw new ServletException(e);
  		} catch (final SQLException e) {
  			throw new ServletException(e);
  		} catch (final IOException e) {
  			throw new ServletException(e);
  		}
  
  		// 2. MAIN CONTROLLERS
  
  		final UsersController usersController = new UsersController(users);
  
  		super.init(new HomeController(users, sessionManager), //
  				usersController, new UseraddController(tx, users,
  						usersController), //
  				new RegionsController(tx, regions), //
  				new AdminGeocampusController(regions, pois, poiTrees), //
  				new SystemController(ds), //
  				new PoisController(regions, pois, poiTrees), //
  				new PoiController(comments, commentManager, searchManager,
  						regions, pois, poiTrees), //
  				new CommentsController(comments, commentManager, searchManager,
  						regions, pois, poiTrees), //
  				new CommentController(comments, commentManager), //
  				new HelpController(), //
  				new LogsController() //
  		);
  
  		// 3. JSON CONTROLLERS
  
  		final String baseURL = getBaseURL();
  
  		final RegionClient regionClient = new RegionClientFromLocal(baseURL,
  				regions, poiTrees);
  
  		final RegionJSONClient regionJSONClient = new RegionJSONClientImpl(
  				regionClient);
  
  		final PoiClient poiClient = new PoiClientFromLocal(baseURL, pois,
  				poiTrees, regions);
  
  		final PoiJSONClient poiJSONClient = new PoiJSONClientImpl(poiClient);
  
  		final CommentClient commentClient = new CommentClientFromLocal(baseURL,
  				comments, commentManager, searchManager);
  
  		final CommentJSONClient commentJSONClient = new CommentJSONClientImpl(
  				commentClient);
  
  		final String consumerKey = getInitParameter("twitter.consumerKey");
  		final String consumerSecret = getInitParameter("twitter.consumerSecret");
  		
  		final TwitterAccess twitter = new ApplicationOnly(consumerKey, consumerSecret);
  		
  		final SessionClient sessionClient = new SessionClientFromLocal(baseURL,
  				sessionManager, twitter);
  
  		final SessionJSONClient sessionJSONClient = new SessionJSONClientImpl(
  				sessionClient);
  
  		this.jsonControllers = new AbstractJSONController[] {
  				new EndpointsJSONController(), //
  				new RegionsJSONController(regionJSONClient), //
  				new UniversitiesJSONController(regions, regionJSONClient), //
  				new PoisJSONController(poiJSONClient), //
  				new CommentsJSONController(pois, commentJSONClient), //
  				new SessionJSONController(sessionManager, sessionJSONClient) //
  		};
  
  		for (final AbstractJSONController jsonController : jsonControllers) {
  
  			jsonController.init(this);
  		}
  	}
  
  	private static final Log log = LogFactory.getLog(BackendServlet.class);
  
  	@Override
  	public void service(final HttpServletRequest request,
  			final HttpServletResponse response) throws IOException,
  			ServletException {
  
  		// 1. REQUEST
  
  		request.setCharacterEncoding(UTF_8);
  
  		// final String host = request.getHeader("Host");
  		final String remoteAddr = request.getRemoteAddr();
  		final String userAgent = request.getHeader("User-Agent");
  		final String remoteUserAttribute = request.getRemoteUser();
  		final String requestURI = request.getRequestURI();
  
  		if (log.isInfoEnabled()) {
  			log.info("remoteAddr: " + remoteAddr//
  					+ ", requestURI: " + requestURI //
  					+ ", userAgent: \"" + userAgent + "\"" //
  					+ ", remoteUser: " + remoteUserAttribute);
  		}
  
  		if (log.isDebugEnabled()) {
  			log.debug("  request.authType: " + request.getAuthType());
  			log.debug("  request.contentType: " + request.getContentType());
  			log.debug("  request.contextPath: " + request.getContextPath());
  			log.debug("  request.localAddr: " + request.getLocalAddr());
  			log.debug("  request.localName: " + request.getLocalName());
  			log.debug("  request.localPort: " + request.getLocalPort());
  			log.debug("  request.method: " + request.getMethod());
  			log.debug("  request.pathInfo: " + request.getPathInfo());
  			log.debug("  request.protocol: " + request.getProtocol());
  			log.debug("  request.queryString: " + request.getQueryString());
  			log.debug("  request.remoteAddr: " + request.getRemoteAddr());
  			log.debug("  request.remoteHost: " + request.getRemoteHost());
  			log.debug("  request.remoteUser: " + request.getRemoteUser());
  			log.debug("  request.requestURI: " + request.getRequestURI());
  			log.debug("  request.scheme: " + request.getScheme());
  			log.debug("  request.serverName: " + request.getServerName());
  			log.debug("  request.serverPort: " + request.getServerPort());
  			for (final Enumeration<?> e = request.getHeaderNames(); e
  					.hasMoreElements();) {
  				final String headerName = e.nextElement().toString();
  				final String headerValue = request.getHeader(headerName);
  				log.debug("  request.header." + headerName + ": " + headerValue);
  			}
  			// Note: We should not log any password here
  		}
  
  		if (requestURI.contains("/json/") || requestURI.endsWith("/json")) {
  
  			serveJSON(request, response);
  
  			return;
  		}
  
  		if (requestURI.contains("/uploads/")) {
  
  			serveUpload(request, response);
  
  			return;
  		}
  
  		final Object displayName = request.getAttribute("displayName");
  		final Object uid = request.getAttribute("uid");
  		final Object eppn = request.getAttribute("eppn");
  		final Object persistentId = request.getAttribute("persistentId");
  
  		if (log.isInfoEnabled()) {
  			log.info("Shibboleth: uid=" + uid //
  					+ ", remoteUser=" + remoteUserAttribute //
  					+ ", eppn=" + eppn //
  					+ ", persistentId=" + persistentId //
  					+ ", displayName=" + displayName);
  		}
  
  		// 2. VALIDATE: SHIBBOLETH MUST BE HERE
  
  		final String remoteUser;
  
  		if (remoteUserAttribute != null) {
  
  			remoteUser = remoteUserAttribute;
  
  		} else if (eppn != null) {
  
  			// We are implementing the same rule as in:
  			// /etc/shibboleth/shibboleth2.xml
  
  			remoteUser = eppn.toString();
  
  		} else if (persistentId != null) {
  
  			remoteUser = persistentId.toString();
  
  		} else {
  
  			remoteUser = null;
  		}
  
  		if (log.isInfoEnabled()) {
  			log.info("Using remoteUser: " + remoteUser);
  		}
  
  