Author: remm Date: Mon Apr 16 16:30:55 2007 New Revision: 529444 URL: http://svn.apache.org/viewvc?view=rev&rev=529444 Log: - Add session browser capabilities in the manager. Let me know if it creates problems (I checked XSS to some extent to, but please double check if you can). - Submitted by Cédrik Lime.
Added: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/JspHelper.java (with props) tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/ tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/BaseSessionComparator.java (with props) tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/ReverseComparator.java (with props) tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/SessionUtils.java (with props) Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java?view=diff&rev=529444&r1=529443&r2=529444 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java Mon Apr 16 16:30:55 2007 @@ -23,6 +23,10 @@ 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; @@ -30,9 +34,14 @@ 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; @@ -50,7 +59,7 @@ * 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> * @@ -63,6 +72,11 @@ 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 /** @@ -100,7 +114,15 @@ } 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")) { @@ -562,6 +584,309 @@ 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 @@ -586,7 +911,7 @@ " <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" + Added: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/JspHelper.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/JspHelper.java?view=auto&rev=529444 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/JspHelper.java (added) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/JspHelper.java Mon Apr 16 16:30:55 2007 @@ -0,0 +1,239 @@ +/* + * 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); + } +} Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/JspHelper.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/BaseSessionComparator.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/BaseSessionComparator.java?view=auto&rev=529444 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/BaseSessionComparator.java (added) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/BaseSessionComparator.java Mon Apr 16 16:30:55 2007 @@ -0,0 +1,47 @@ +/* + * 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)); + } +} Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/BaseSessionComparator.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/ReverseComparator.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/ReverseComparator.java?view=auto&rev=529444 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/ReverseComparator.java (added) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/ReverseComparator.java Mon Apr 16 16:30:55 2007 @@ -0,0 +1,44 @@ +/* + * 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); + } +} Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/ReverseComparator.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/SessionUtils.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/SessionUtils.java?view=auto&rev=529444 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/SessionUtils.java (added) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/SessionUtils.java Mon Apr 16 16:30:55 2007 @@ -0,0 +1,267 @@ +/* + * 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; + } + } +} Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/manager/util/SessionUtils.java ------------------------------------------------------------------------------ svn:eol-style = native --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]