import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
+import org.apache.catalina.Session;
+import org.apache.catalina.manager.util.BaseSessionComparator;
+import org.apache.catalina.manager.util.ReverseComparator;
+import org.apache.catalina.manager.util.SessionUtils;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.ServerInfo;
import org.apache.tomcat.util.http.fileupload.DiskFileUpload;
* makes it easier to administrate.
* <p>
* However if you use a software that parses the output of
-* <code>ManagerServlet</code you won't be able to upgrade
+* <code>ManagerServlet</code> you won't be able to upgrade
* to this Servlet since the output are not in the
* same format ar from <code>ManagerServlet</code>
*
public final class HTMLManagerServlet extends ManagerServlet {
+ protected static final String APPLICATION_MESSAGE = "message";
+ protected static final String APPLICATION_ERROR = "error";
+ protected String sessionsListJspPath = "/sessionsList.jsp";
+ protected String sessionDetailJspPath = "/sessionDetail.jsp";
+
// --------------------------------------------------------- Public Methods
/**
} else if (command.equals("/undeploy")) {
message = undeploy(path);
} else if (command.equals("/sessions")) {
- message = sessions(path);
+ //message = sessions(path);
+ try {
+ doSessions(path, request, response);
+ return;
+ } catch (Exception e) {
+ log("HTMLManagerServlet.sessions[" + path + "]", e);
+ message = sm.getString("managerServlet.exception",
+ e.toString());
+ }
} else if (command.equals("/start")) {
message = start(path);
} else if (command.equals("/stop")) {
return stringWriter.toString();
}
+ /**
+ * @see javax.servlet.Servlet#getServletInfo()
+ */
+ public String getServletInfo() {
+ return "HTMLManagerServlet, Copyright (c) The Apache Software Foundation";
+ }
+
+ /**
+ * @see javax.servlet.GenericServlet#init()
+ */
+ public void init() throws ServletException {
+ super.init();
+ }
+
+ // ------------------------------------------------ Sessions administration
+
+ /**
+ *
+ * @param req
+ * @param resp
+ * @throws ServletException
+ * @throws IOException
+ */
+ protected void doSessions(String path, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ req.setAttribute("path", path);
+ String action = req.getParameter("action");
+ if (debug >= 1) {
+ log("sessions: Session action '" + action + "' for web application at '" + path + "'");
+ }
+ if ("sessionDetail".equals(action)) {
+ String sessionId = req.getParameter("sessionId");
+ displaySessionDetailPage(req, resp, path, sessionId);
+ return;
+ } else if ("invalidateSessions".equals(action)) {
+ String[] sessionIds = req.getParameterValues("sessionIds");
+ int i = invalidateSessions(path, sessionIds);
+ req.setAttribute(APPLICATION_MESSAGE, "" + i + " sessions invalidated.");
+ } else if ("removeSessionAttribute".equals(action)) {
+ String sessionId = req.getParameter("sessionId");
+ String name = req.getParameter("attributeName");
+ boolean removed = removeSessionAttribute(path, sessionId, name);
+ String outMessage = removed ? "Session attribute '" + name + "' removed." : "Session did not contain any attribute named '" + name + "'";
+ req.setAttribute(APPLICATION_MESSAGE, outMessage);
+ resp.sendRedirect(resp.encodeRedirectURL(req.getRequestURL().append("?path=").append(path).append("&action=sessionDetail&sessionId=").append(sessionId).toString()));
+ return;
+ } // else
+ displaySessionsListPage(path, req, resp);
+ }
+
+ protected Session[] getSessionsForPath(String path) {
+ if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+ throw new IllegalArgumentException(sm.getString("managerServlet.invalidPath",
+ RequestUtil.filter(path)));
+ }
+ String displayPath = path;
+ if( path.equals("/") )
+ path = "";
+ Context context = (Context) host.findChild(path);
+ if (null == context) {
+ throw new IllegalArgumentException(sm.getString("managerServlet.noContext",
+ RequestUtil.filter(displayPath)));
+ }
+ Session[] sessions = context.getManager().findSessions();
+ return sessions;
+ }
+ protected Session getSessionForPathAndId(String path, String id) throws IOException {
+ if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+ throw new IllegalArgumentException(sm.getString("managerServlet.invalidPath",
+ RequestUtil.filter(path)));
+ }
+ String displayPath = path;
+ if( path.equals("/") )
+ path = "";
+ Context context = (Context) host.findChild(path);
+ if (null == context) {
+ throw new IllegalArgumentException(sm.getString("managerServlet.noContext",
+ RequestUtil.filter(displayPath)));
+ }
+ Session session = context.getManager().findSession(id);
+ return session;
+ }
+
+ /**
+ *
+ * @param req
+ * @param resp
+ * @throws ServletException
+ * @throws IOException
+ */
+ protected void displaySessionsListPage(String path, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ List/*<Session>*/ activeSessions = Arrays.asList(getSessionsForPath(path));
+ String sortBy = req.getParameter("sort");
+ String orderBy = null;
+ if (null != sortBy && !"".equals(sortBy.trim())) {
+ Comparator comparator = getComparator(sortBy);
+ if (comparator != null) {
+ orderBy = req.getParameter("order");
+ if ("DESC".equalsIgnoreCase(orderBy)) {
+ comparator = new ReverseComparator(comparator);
+ // orderBy = "ASC";
+ } else {
+ //orderBy = "DESC";
+ }
+ try {
+ Collections.sort(activeSessions, comparator);
+ } catch (IllegalStateException ise) {
+ // at least 1 of the sessions is invalidated
+ req.setAttribute(APPLICATION_ERROR, "Can't sort session list: one session is invalidated");
+ }
+ } else {
+ log("WARNING: unknown sort order: " + sortBy);
+ }
+ }
+ // keep sort order
+ req.setAttribute("sort", sortBy);
+ req.setAttribute("order", orderBy);
+ req.setAttribute("activeSessions", activeSessions);
+ //strong>NOTE</strong> - This header will be overridden
+ // automatically if a <code>RequestDispatcher.forward()</code> call is
+ // ultimately invoked.
+ resp.setHeader("Pragma", "No-cache"); // HTTP 1.0
+ resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1
+ resp.setDateHeader("Expires", 0); // 0 means now
+ getServletContext().getRequestDispatcher(sessionsListJspPath).include(req, resp);
+ }
+
+ /**
+ *
+ * @param req
+ * @param resp
+ * @throws ServletException
+ * @throws IOException
+ */
+ protected void displaySessionDetailPage(HttpServletRequest req, HttpServletResponse resp, String path, String sessionId) throws ServletException, IOException {
+ Session session = getSessionForPathAndId(path, sessionId);
+ //strong>NOTE</strong> - This header will be overridden
+ // automatically if a <code>RequestDispatcher.forward()</code> call is
+ // ultimately invoked.
+ resp.setHeader("Pragma", "No-cache"); // HTTP 1.0
+ resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1
+ resp.setDateHeader("Expires", 0); // 0 means now
+ req.setAttribute("currentSession", session);
+ getServletContext().getRequestDispatcher(sessionDetailJspPath).include(req, resp);
+ }
+
+ /**
+ * Invalidate HttpSessions
+ * @param sessionIds
+ * @return number of invalidated sessions
+ * @throws IOException
+ */
+ public int invalidateSessions(String path, String[] sessionIds) throws IOException {
+ if (null == sessionIds) {
+ return 0;
+ }
+ int nbAffectedSessions = 0;
+ for (int i = 0; i < sessionIds.length; ++i) {
+ String sessionId = sessionIds[i];
+ HttpSession session = getSessionForPathAndId(path, sessionId).getSession();
+ if (null == session) {
+ // Shouldn't happen, but let's play nice...
+ if (debug >= 1) {
+ log("WARNING: can't invalidate null session " + sessionId);
+ }
+ continue;
+ }
+ try {
+ session.invalidate();
+ ++nbAffectedSessions;
+ if (debug >= 1) {
+ log("Invalidating session id " + sessionId);
+ }
+ } catch (IllegalStateException ise) {
+ if (debug >= 1) {
+ log("Can't invalidate already invalidated session id " + sessionId);
+ }
+ }
+ }
+ return nbAffectedSessions;
+ }
+
+ /**
+ * Removes an attribute from an HttpSession
+ * @param sessionId
+ * @param attributeName
+ * @return true if there was an attribute removed, false otherwise
+ * @throws IOException
+ */
+ public boolean removeSessionAttribute(String path, String sessionId, String attributeName) throws IOException {
+ HttpSession session = getSessionForPathAndId(path, sessionId).getSession();
+ if (null == session) {
+ // Shouldn't happen, but let's play nice...
+ if (debug >= 1) {
+ log("WARNING: can't remove attribute '" + attributeName + "' for null session " + sessionId);
+ }
+ return false;
+ }
+ boolean wasPresent = (null != session.getAttribute(attributeName));
+ try {
+ session.removeAttribute(attributeName);
+ } catch (IllegalStateException ise) {
+ if (debug >= 1) {
+ log("Can't remote attribute '" + attributeName + "' for invalidated session id " + sessionId);
+ }
+ }
+ return wasPresent;
+ }
+
+ /**
+ * Sets the maximum inactive interval (session timeout) an HttpSession
+ * @param sessionId
+ * @param maxInactiveInterval in seconds
+ * @return old value for maxInactiveInterval
+ * @throws IOException
+ */
+ public int setSessionMaxInactiveInterval(String path, String sessionId, int maxInactiveInterval) throws IOException {
+ HttpSession session = getSessionForPathAndId(path, sessionId).getSession();
+ if (null == session) {
+ // Shouldn't happen, but let's play nice...
+ if (debug >= 1) {
+ log("WARNING: can't set timout for null session " + sessionId);
+ }
+ return 0;
+ }
+ try {
+ int oldMaxInactiveInterval = session.getMaxInactiveInterval();
+ session.setMaxInactiveInterval(maxInactiveInterval);
+ return oldMaxInactiveInterval;
+ } catch (IllegalStateException ise) {
+ if (debug >= 1) {
+ log("Can't set MaxInactiveInterval '" + maxInactiveInterval + "' for invalidated session id " + sessionId);
+ }
+ return 0;
+ }
+ }
+
+ protected Comparator getComparator(String sortBy) {
+ Comparator comparator = null;
+ if ("CreationTime".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return new Date(session.getCreationTime());
+ }
+ };
+ } else if ("id".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return session.getId();
+ }
+ };
+ } else if ("LastAccessedTime".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return new Date(session.getLastAccessedTime());
+ }
+ };
+ } else if ("MaxInactiveInterval".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return new Date(session.getMaxInactiveInterval());
+ }
+ };
+ } else if ("new".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return Boolean.valueOf(session.getSession().isNew());
+ }
+ };
+ } else if ("locale".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return JspHelper.guessDisplayLocaleFromSession(session);
+ }
+ };
+ } else if ("user".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return JspHelper.guessDisplayUserFromSession(session);
+ }
+ };
+ } else if ("UsedTime".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return new Date(SessionUtils.getUsedTimeForSession(session));
+ }
+ };
+ } else if ("InactiveTime".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return new Date(SessionUtils.getInactiveTimeForSession(session));
+ }
+ };
+ } else if ("TTL".equalsIgnoreCase(sortBy)) {
+ comparator = new BaseSessionComparator() {
+ public Comparable getComparableObject(Session session) {
+ return new Date(SessionUtils.getTTLForSession(session));
+ }
+ };
+ }
+ //TODO: complete this to TTL, etc.
+ return comparator;
+ }
+
// ------------------------------------------------------ Private Constants
// These HTML sections are broken in relatively small sections, because of
" <td class=\"row-left\" bgcolor=\"{5}\"><small><a href=\"{0}\">{0}</a></small></td>\n" +
" <td class=\"row-left\" bgcolor=\"{5}\"><small>{1}</small></td>\n" +
" <td class=\"row-center\" bgcolor=\"{5}\"><small>{2}</small></td>\n" +
- " <td class=\"row-center\" bgcolor=\"{5}\"><small><a href=\"{3}\">{4}</a></small></td>\n";
+ " <td class=\"row-center\" bgcolor=\"{5}\"><small><a href=\"{3}\" target=\"_new\">{4}</a></small></td>\n";
private static final String MANAGER_APP_ROW_BUTTON_SECTION =
" <td class=\"row-left\" bgcolor=\"{8}\">\n" +
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.apache.catalina.manager;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+import org.apache.catalina.Session;
+import org.apache.catalina.manager.util.SessionUtils;
+
+
+/**
+ * Helper JavaBean for JSPs, because JSTL 1.1/EL 2.0 is too dumb to
+ * to what I need (call methods with parameters), or I am too dumb to use it correctly. :)
+ * @author Cédrik LIME
+ */
+public class JspHelper {
+
+ private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
+ private static final String DATE_FORMAT = "yyyy-MM-dd";
+ private static final String TIME_FORMAT = "HH:mm:ss";
+
+ /**
+ * Public constructor, so that this class can be considered a JavaBean
+ */
+ private JspHelper() {
+ super();
+ }
+
+ /**
+ * Try to get user locale from the session, if possible.
+ * IMPLEMENTATION NOTE: this method has explicit support for Tapestry 3 and Struts 1.x
+ * @param in_session
+ * @return String
+ */
+ public static String guessDisplayLocaleFromSession(Session in_session) {
+ return localeToString(SessionUtils.guessLocaleFromSession(in_session));
+ }
+ private static String localeToString(Locale locale) {
+ if (locale != null) {
+ return locale.toString();//locale.getDisplayName();
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Try to get user name from the session, if possible.
+ * @param in_session
+ * @return String
+ */
+ public static String guessDisplayUserFromSession(Session in_session) {
+ Object user = SessionUtils.guessUserFromSession(in_session);
+ return escapeXml(user);
+ }
+
+
+ public static String getDisplayCreationTimeForSession(Session in_session) {
+ try {
+ DateFormat formatter = new SimpleDateFormat(DATE_TIME_FORMAT);
+ return formatter.format(new Date(in_session.getCreationTime()));
+ } catch (IllegalStateException ise) {
+ //ignore: invalidated session
+ return "";
+ }
+ }
+
+ public static String getDisplayLastAccessedTimeForSession(Session in_session) {
+ try {
+ DateFormat formatter = new SimpleDateFormat(DATE_TIME_FORMAT);
+ return formatter.format(new Date(in_session.getLastAccessedTime()));
+ } catch (IllegalStateException ise) {
+ //ignore: invalidated session
+ return "";
+ }
+ }
+
+ public static String getDisplayUsedTimeForSession(Session in_session) {
+ return secondsToTimeString(SessionUtils.getUsedTimeForSession(in_session)/1000);
+ }
+
+ public static String getDisplayTTLForSession(Session in_session) {
+ return secondsToTimeString(SessionUtils.getTTLForSession(in_session)/1000);
+ }
+
+ public static String getDisplayInactiveTimeForSession(Session in_session) {
+ return secondsToTimeString(SessionUtils.getInactiveTimeForSession(in_session)/1000);
+ }
+
+ public static String secondsToTimeString(long in_seconds) {
+ StringBuffer buff = new StringBuffer(9);
+ long rest = in_seconds;
+ long hour = rest / 3600;
+ rest = rest % 3600;
+ long minute = rest / 60;
+ rest = rest % 60;
+ long second = rest;
+ if (hour < 10) {
+ buff.append('0');
+ }
+ buff.append(hour);
+ buff.append(':');
+ if (minute < 10) {
+ buff.append('0');
+ }
+ buff.append(minute);
+ buff.append(':');
+ if (second < 10) {
+ buff.append('0');
+ }
+ buff.append(second);
+ return buff.toString();
+ }
+
+
+ /**
+ * Following copied from org.apache.taglibs.standard.tag.common.core.OutSupport v1.1.2
+ *
+ * Optimized to create no extra objects and write directly
+ * to the JspWriter using blocks of escaped and unescaped characters
+ *
+ */
+ private static void writeEscapedXml(char[] buffer, int length, Writer w) throws IOException {
+ int start = 0;
+
+ for (int i = 0; i < length; i++) {
+ char c = buffer[i];
+ if (c <= HIGHEST_SPECIAL) {
+ char[] escaped = specialCharactersRepresentation[c];
+ if (escaped != null) {
+ // add unescaped portion
+ if (start < i) {
+ w.write(buffer,start,i-start);
+ }
+ // add escaped xml
+ w.write(escaped);
+ start = i + 1;
+ }
+ }
+ }
+ // add rest of unescaped portion
+ if (start < length) {
+ w.write(buffer,start,length-start);
+ }
+ }
+
+
+ /*
+ * Following copied from org.apache.taglibs.standard.tag.common.core.Util v1.1.2
+ */
+
+ private static final int HIGHEST_SPECIAL = '>';
+ private static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][];
+ static {
+ specialCharactersRepresentation['&'] = "&".toCharArray();
+ specialCharactersRepresentation['<'] = "<".toCharArray();
+ specialCharactersRepresentation['>'] = ">".toCharArray();
+ specialCharactersRepresentation['"'] = """.toCharArray();
+ specialCharactersRepresentation['\''] = "'".toCharArray();
+ }
+
+ public static String escapeXml(Object obj) {
+ return obj == null ? "" : escapeXml(String.valueOf(obj));
+ }
+ /**
+ * Performs the following substring replacements
+ * (to facilitate output to XML/HTML pages):
+ *
+ * & -> &
+ * < -> <
+ * > -> >
+ * " -> "
+ * ' -> '
+ *
+ * See also OutSupport.writeEscapedXml().
+ */
+ public static String escapeXml(String buffer) {
+ if (buffer == null) {
+ return "";
+ }
+ int start = 0;
+ int length = buffer.length();
+ char[] arrayBuffer = buffer.toCharArray();
+ StringBuffer escapedBuffer = null;
+
+ for (int i = 0; i < length; i++) {
+ char c = arrayBuffer[i];
+ if (c <= HIGHEST_SPECIAL) {
+ char[] escaped = specialCharactersRepresentation[c];
+ if (escaped != null) {
+ // create StringBuffer to hold escaped xml string
+ if (start == 0) {
+ escapedBuffer = new StringBuffer(length + 5);
+ }
+ // add unescaped portion
+ if (start < i) {
+ escapedBuffer.append(arrayBuffer,start,i-start);
+ }
+ start = i + 1;
+ // add escaped xml
+ escapedBuffer.append(escaped);
+ }
+ }
+ }
+ // no xml escaping was necessary
+ if (start == 0) {
+ return buffer;
+ }
+ // add rest of unescaped portion
+ if (start < length) {
+ escapedBuffer.append(arrayBuffer,start,length-start);
+ }
+ return escapedBuffer.toString();
+ }
+
+ public static String formatNumber(long number) {
+ return NumberFormat.getNumberInstance().format(number);
+ }
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.apache.catalina.manager.util;
+
+import java.util.Comparator;
+
+import org.apache.catalina.Session;
+
+/**
+ * Comparator which permits to compare on a session's content
+ * @author Cédrik LIME
+ */
+public abstract class BaseSessionComparator implements Comparator {
+
+ /**
+ *
+ */
+ public BaseSessionComparator() {
+ super();
+ }
+
+ public abstract Comparable getComparableObject(Session session);
+
+ /* (non-Javadoc)
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ public final int compare(Object o1, Object o2) {
+ Comparable c1 = getComparableObject((Session)o1);
+ Comparable c2 = getComparableObject((Session)o2);
+ return c1==null ? (c2==null ? 0 : -1) : (c2==null ? 1 : c1.compareTo(c2));
+ }
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.apache.catalina.manager.util;
+
+import java.util.Comparator;
+
+/**
+ * Comparator which reverse the sort order
+ * @author Cédrik LIME
+ */
+public class ReverseComparator implements Comparator {
+ protected Comparator comparator;
+
+ /**
+ *
+ */
+ public ReverseComparator(Comparator comparator) {
+ super();
+ this.comparator = comparator;
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ public int compare(Object o1, Object o2) {
+ int returnValue = comparator.compare(o1, o2);
+ return (- returnValue);
+ }
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.apache.catalina.manager.util;
+
+import java.lang.reflect.Method;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Locale;
+
+import javax.security.auth.Subject;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.Session;
+
+/**
+ * Utility methods on HttpSessions...
+ * @author Cédrik LIME
+ */
+public class SessionUtils {
+
+ /**
+ *
+ */
+ private SessionUtils() {
+ super();
+ }
+
+ /**
+ * The session attributes key under which the user's selected
+ * <code>java.util.Locale</code> is stored, if any.
+ */
+ // org.apache.struts.Globals.LOCALE_KEY
+ private static final String STRUTS_LOCALE_KEY = "org.apache.struts.action.LOCALE";//$NON-NLS-1$
+ // javax.servlet.jsp.jstl.core.Config.FMT_LOCALE
+ private static final String JSTL_LOCALE_KEY = "javax.servlet.jsp.jstl.fmt.locale";//$NON-NLS-1$
+ // org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME
+ private static final String SPRING_LOCALE_KEY = "org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE";//$NON-NLS-1$
+ /**
+ * Lower and upper-case strings will be dynamically generated. Put mid-capitalised strings here!
+ */
+ private static final String[] LOCALE_TEST_ATTRIBUTES = new String[] {
+ STRUTS_LOCALE_KEY, SPRING_LOCALE_KEY, JSTL_LOCALE_KEY, "Locale", "java.util.Locale" };
+ /**
+ * Lower and upper-case strings will be dynamically generated. Put mid-capitalised strings here!
+ */
+ private static final String[] USER_TEST_ATTRIBUTES = new String[] {
+ "Login", "User", "userName", "UserName", "Utilisateur" };
+
+ /**
+ * Try to get user locale from the session, if possible.
+ * IMPLEMENTATION NOTE: this method has explicit support for Tapestry 3, Struts 1.x and Spring
+ * JSF check the browser meta tag "accept languages" to choose what langage to display.
+ * @param in_session
+ * @return String
+ */
+ public static Locale guessLocaleFromSession(final Session in_session) {
+ return guessLocaleFromSession(in_session.getSession());
+ }
+ public static Locale guessLocaleFromSession(final HttpSession in_session) {
+ if (null == in_session) {
+ return null;
+ }
+ try {
+ Locale locale = null;
+
+ // First search "known locations"
+ for (int i = 0; i < LOCALE_TEST_ATTRIBUTES.length; ++i) {
+ Object obj = in_session.getAttribute(LOCALE_TEST_ATTRIBUTES[i]);
+ if (null != obj && obj instanceof Locale) {
+ locale = (Locale) obj;
+ break;
+ }
+ obj = in_session.getAttribute(LOCALE_TEST_ATTRIBUTES[i].toLowerCase());
+ if (null != obj && obj instanceof Locale) {
+ locale = (Locale) obj;
+ break;
+ }
+ obj = in_session.getAttribute(LOCALE_TEST_ATTRIBUTES[i].toUpperCase());
+ if (null != obj && obj instanceof Locale) {
+ locale = (Locale) obj;
+ break;
+ }
+ }
+
+ if (null != locale) {
+ return locale;
+ }
+
+ // Tapestry 3.0: Engine stored in session under "org.apache.tapestry.engine:" + config.getServletName()
+ // TODO: Tapestry 4+
+ {
+ final List tapestryArray = new ArrayList();
+ for (Enumeration enumeration = in_session.getAttributeNames(); enumeration.hasMoreElements();) {
+ String name = (String) enumeration.nextElement();
+ if (name.indexOf("tapestry") > -1 && name.indexOf("engine") > -1 && null != in_session.getAttribute(name)) {//$NON-NLS-1$ //$NON-NLS-2$
+ tapestryArray.add(in_session.getAttribute(name));
+ }
+ }
+ if (tapestryArray.size() == 1) {
+ // found a potential Engine! Let's call getLocale() on it.
+ Object probableEngine = tapestryArray.get(0);
+ if (null != probableEngine) {
+ try {
+ Method readMethod = probableEngine.getClass().getMethod("getLocale", null);//$NON-NLS-1$
+ if (null != readMethod) {
+ // Call the property getter and return the value
+ Object possibleLocale = readMethod.invoke(probableEngine, null);
+ if (null != possibleLocale && possibleLocale instanceof Locale) {
+ locale = (Locale) possibleLocale;
+ }
+ }
+ } catch (Exception e) {
+ // stay silent
+ }
+ }
+ }
+ }
+
+ if (null != locale) {
+ return locale;
+ }
+
+ // Last guess: iterate over all attributes, to find a Locale
+ // If there is only one, consider it to be /the/ locale
+ {
+ final List localeArray = new ArrayList();
+ for (Enumeration enumeration = in_session.getAttributeNames(); enumeration.hasMoreElements();) {
+ String name = (String) enumeration.nextElement();
+ Object obj = in_session.getAttribute(name);
+ if (null != obj && obj instanceof Locale) {
+ localeArray.add(obj);
+ }
+ }
+ if (localeArray.size() == 1) {
+ locale = (Locale) localeArray.get(0);
+ }
+ }
+
+ return locale;
+ } catch (IllegalStateException ise) {
+ //ignore: invalidated session
+ return null;
+ }
+ }
+
+ /**
+ * Try to get user from the session, if possible.
+ * @param in_session
+ * @return Object
+ */
+ public static Object guessUserFromSession(final Session in_session) {
+ if (null == in_session) {
+ return null;
+ }
+ if (in_session.getPrincipal() != null) {
+ return in_session.getPrincipal().getName();
+ }
+ HttpSession httpSession = in_session.getSession();
+ try {
+ Object user = null;
+ // First search "known locations"
+ for (int i = 0; i < USER_TEST_ATTRIBUTES.length; ++i) {
+ Object obj = httpSession.getAttribute(USER_TEST_ATTRIBUTES[i]);
+ if (null != obj) {
+ user = obj;
+ break;
+ }
+ obj = httpSession.getAttribute(USER_TEST_ATTRIBUTES[i].toLowerCase());
+ if (null != obj) {
+ user = obj;
+ break;
+ }
+ obj = httpSession.getAttribute(USER_TEST_ATTRIBUTES[i].toUpperCase());
+ if (null != obj) {
+ user = obj;
+ break;
+ }
+ }
+
+ if (null != user) {
+ return user;
+ }
+
+ // Last guess: iterate over all attributes, to find a java.security.Principal or javax.security.auth.Subject
+ // If there is only one, consider it to be /the/ user
+ {
+ final List principalArray = new ArrayList();
+ for (Enumeration enumeration = httpSession.getAttributeNames(); enumeration.hasMoreElements();) {
+ String name = (String) enumeration.nextElement();
+ Object obj = httpSession.getAttribute(name);
+ if (null != obj && (obj instanceof Principal || obj instanceof Subject)) {
+ principalArray.add(obj);
+ }
+ // This workaround for JDK 1.3 compatibility. For JDK 1.4+, use previous (commented) instanceof.
+// try {
+// Class subjectClass = Class.forName("javax.security.auth.Subject", true, Thread.currentThread().getContextClassLoader());
+// if (subjectClass.isInstance(obj)) {
+// principalArray.add(obj);
+// }
+// } catch (ClassNotFoundException cnfe) {
+// // This is JDK 1.3: javax.security.auth.Subject does not exist; do nothing
+// }
+ }
+ if (principalArray.size() == 1) {
+ user = principalArray.get(0);
+ }
+ }
+
+ if (null != user) {
+ return user;
+ }
+
+ return user;
+ } catch (IllegalStateException ise) {
+ //ignore: invalidated session
+ return null;
+ }
+ }
+
+
+ public static long getUsedTimeForSession(Session in_session) {
+ try {
+ long diffMilliSeconds = in_session.getLastAccessedTime() - in_session.getCreationTime();
+ return diffMilliSeconds;
+ } catch (IllegalStateException ise) {
+ //ignore: invalidated session
+ return -1;
+ }
+ }
+
+ public static long getTTLForSession(Session in_session) {
+ try {
+ long diffMilliSeconds = (1000*in_session.getMaxInactiveInterval()) - (System.currentTimeMillis() - in_session.getLastAccessedTime());
+ return diffMilliSeconds;
+ } catch (IllegalStateException ise) {
+ //ignore: invalidated session
+ return -1;
+ }
+ }
+
+ public static long getInactiveTimeForSession(Session in_session) {
+ try {
+ long diffMilliSeconds = System.currentTimeMillis() - in_session.getLastAccessedTime();
+ return diffMilliSeconds;
+ } catch (IllegalStateException ise) {
+ //ignore: invalidated session
+ return -1;
+ }
+ }
+}