/** @param args */ public static void main(final String[] args) { LogUtils.initializeLogging(); if (args.length != 1) { LOGGER.fatal("You must specify the output directory"); return; } final String dbname = "generate_schema"; Connection connection = null; try { // generate example database final DataSource datasource = Utilities.createMemoryDataSource(dbname); connection = datasource.getConnection(); final String baseDir = "fll/resources/challenge-descriptors/"; final String challengeName = "example-database.xml"; final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); final URL challengeUrl = classLoader.getResource(baseDir + challengeName); final InputStream stream = challengeUrl.openStream(); final Reader reader = new InputStreamReader(stream, Utilities.DEFAULT_CHARSET); final Document document = ChallengeParser.parse(reader); GenerateDB.generateDB(document, connection); SchemaAnalyzer analyzer = new SchemaAnalyzer(); final Config config = new HsqlMemConfig(); config.setAdsEnabled(false); config.setDb(dbname); config.setHighQuality(true); config.setSchema("PUBLIC"); config.setUser("SA"); config.setOutputDir(args[0]); analyzer.analyze(config); } catch (final SQLException e) { LOGGER.fatal("Error talking to the database", e); } catch (final Exception e) { LOGGER.fatal("Error creating the diagram", e); } finally { // clean up database SQLFunctions.close(connection); } }
/** Populate page context for selectTournament.jsp. */ public class SelectTournament { private static final Logger LOGGER = LogUtils.getLogger(); public static void populateContext(final HttpSession session, final PageContext page) { final DataSource importDataSource = SessionAttributes.getNonNullAttribute(session, "dbimport", DataSource.class); Connection connection = null; try { connection = importDataSource.getConnection(); final List<Tournament> tournaments = Tournament.getTournaments(connection); page.setAttribute("tournaments", tournaments); } catch (final SQLException e) { LOGGER.error("There was an error talking to the database", e); throw new RuntimeException("There was an error talking to the database", e); } finally { SQLFunctions.close(connection); } } }
@WebServlet("/scoreboard/Top10") public class Top10 extends BaseFLLServlet { private static final Logger LOGGER = LogUtils.getLogger(); /** Max number of characters in a team name to display. */ public static final int MAX_TEAM_NAME = 12; /** Max number of characters in an organization to display. */ public static final int MAX_ORG_NAME = 20; @SuppressFBWarnings( value = {"SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING"}, justification = "Determine sort order based upon winner criteria") protected void processRequest( final HttpServletRequest request, final HttpServletResponse response, final ServletContext application, final HttpSession session) throws IOException, ServletException { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Entering doPost"); } final DataSource datasource = ApplicationAttributes.getDataSource(application); final Formatter formatter = new Formatter(response.getWriter()); final String showOrgStr = request.getParameter("showOrganization"); final boolean showOrg = null == showOrgStr ? true : Boolean.parseBoolean(showOrgStr); PreparedStatement prep = null; ResultSet rs = null; Connection connection = null; try { connection = datasource.getConnection(); final int currentTournament = Queries.getCurrentTournament(connection); final int maxScoreboardRound = TournamentParameters.getMaxScoreboardPerformanceRound(connection, currentTournament); final Integer divisionIndexObj = SessionAttributes.getAttribute(session, "divisionIndex", Integer.class); int divisionIndex; if (null == divisionIndexObj) { divisionIndex = 0; } else { divisionIndex = divisionIndexObj.intValue(); } ++divisionIndex; final List<String> divisions = Queries.getAwardGroups(connection); if (divisionIndex >= divisions.size()) { divisionIndex = 0; } session.setAttribute("divisionIndex", Integer.valueOf(divisionIndex)); formatter.format( "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">%n"); formatter.format("<html>%n"); formatter.format("<head>%n"); formatter.format("<link rel='stylesheet' type='text/css' href='../style/fll-sw.css' />%n"); formatter.format("<link rel='stylesheet' type='text/css' href='score_style.css' />%n"); formatter.format( "<meta http-equiv='refresh' content='%d' />%n", GlobalParameters.getIntGlobalParameter(connection, GlobalParameters.DIVISION_FLIP_RATE)); formatter.format("</head>%n"); formatter.format("<body class='scoreboard'>%n"); formatter.format("<table border='1' cellpadding='2' cellspacing='0' width='98%%'>%n"); formatter.format("<colgroup>%n"); formatter.format("<col width='30px' />%n"); formatter.format("<col width='75px' />%n"); formatter.format("<col />%n"); if (showOrg) { formatter.format("<col />%n"); } formatter.format("<col width='70px' />%n"); formatter.format("</colgroup>%n"); if (!divisions.isEmpty()) { formatter.format("<tr>%n"); int numColumns = 5; if (!showOrg) { --numColumns; } formatter.format( "<th colspan='%d' bgcolor='%s'>Top Performance Scores: %s</th>", numColumns, Queries.getColorForIndex(divisionIndex), divisions.get(divisionIndex)); formatter.format("</tr>%n"); final ChallengeDescription challengeDescription = ApplicationAttributes.getChallengeDescription(application); final WinnerType winnerCriteria = challengeDescription.getWinner(); prep = connection.prepareStatement( "SELECT Teams.TeamName, Teams.Organization, Teams.TeamNumber, T2.MaxOfComputedScore" // + " FROM (SELECT TeamNumber, " // + winnerCriteria.getMinMaxString() + "(ComputedTotal) AS MaxOfComputedScore" // + " FROM verified_performance WHERE Tournament = ? " + " AND NoShow = False" // + " AND Bye = False" // + " AND RunNumber <= ?" // + " GROUP BY TeamNumber) AS T2" + " JOIN Teams ON Teams.TeamNumber = T2.TeamNumber, current_tournament_teams" + " WHERE Teams.TeamNumber = current_tournament_teams.TeamNumber" // + " AND current_tournament_teams.event_division = ?" + " ORDER BY T2.MaxOfComputedScore " + winnerCriteria.getSortString()); prep.setInt(1, currentTournament); prep.setInt(2, maxScoreboardRound); prep.setString(3, divisions.get(divisionIndex)); rs = prep.executeQuery(); double prevScore = -1; int i = 1; int rank = 0; while (rs.next()) { final double score = rs.getDouble("MaxOfComputedScore"); if (!FP.equals(score, prevScore, 1E-6)) { rank = i; } formatter.format("<tr>%n"); formatter.format("<td class='center'>%d</td>%n", rank); formatter.format("<td class='right'>%d</td>%n", rs.getInt("TeamNumber")); String teamName = rs.getString("TeamName"); if (null == teamName) { teamName = " "; } formatter.format("<td class='left truncate'>%s</td>%n", teamName); if (showOrg) { String organization = rs.getString("Organization"); if (null == organization) { organization = " "; } formatter.format("<td class='left truncate'>%s</td>%n", organization); } formatter.format( "<td class='right'>%s</td>%n", Utilities.NUMBER_FORMAT_INSTANCE.format(score)); formatter.format("</tr>"); prevScore = score; ++i; } // end while next } // end divisions not empty formatter.format("</table>%n"); formatter.format("</body>%n"); formatter.format("</html>%n"); } catch (final SQLException e) { throw new RuntimeException("Error talking to the database", e); } finally { SQLFunctions.close(rs); SQLFunctions.close(prep); SQLFunctions.close(connection); } if (LOGGER.isTraceEnabled()) { LOGGER.trace("Exiting doPost"); } } }
/** Create a new playoff division. */ @WebServlet("/playoff/CreatePlayoffDivision") public class CreatePlayoffDivision extends BaseFLLServlet { private static final Logger LOGGER = LogUtils.getLogger(); /** * Populate the context for create_playoff_division.jsp. * * @param application */ public static void populateContext( final ServletContext application, final PageContext pageContext) { final DataSource datasource = ApplicationAttributes.getDataSource(application); Connection connection = null; try { connection = datasource.getConnection(); final int currentTournamentID = Queries.getCurrentTournament(connection); final List<String> judgingStations = Queries.getJudgingStations(connection, currentTournamentID); pageContext.setAttribute("judgingStations", judgingStations); final List<String> awardGroups = Queries.getAwardGroups(connection, currentTournamentID); pageContext.setAttribute("awardGroups", awardGroups); } catch (final SQLException sqle) { LOGGER.error(sqle, sqle); throw new RuntimeException("Error talking to the database", sqle); } finally { SQLFunctions.close(connection); } } @Override protected void processRequest( final HttpServletRequest request, final HttpServletResponse response, final ServletContext application, final HttpSession session) throws IOException, ServletException { final StringBuilder message = new StringBuilder(); final String existingMessage = SessionAttributes.getMessage(session); if (null != existingMessage) { message.append(existingMessage); } String redirect = "index.jsp"; final DataSource datasource = ApplicationAttributes.getDataSource(application); Connection connection = null; try { connection = datasource.getConnection(); final PlayoffSessionData data = SessionAttributes.getNonNullAttribute( session, PlayoffIndex.SESSION_DATA, PlayoffSessionData.class); final Tournament currentTournament = data.getCurrentTournament(); final int currentTournamentID = currentTournament.getTournamentID(); final List<String> playoffDivisions = Playoff.getPlayoffBrackets(connection, currentTournamentID); if (null != request.getParameter("selected_teams")) { final String bracketName = request.getParameter("bracket_name"); if (null == bracketName || "".equals(bracketName)) { message.append("<p class='error'>You need to specify a name for the playoff bracket</p>"); redirect = "create_playoff_division.jsp"; } else if (playoffDivisions.contains(bracketName)) { message.append( "<p class='error'>The playoff bracket '" + bracketName + "' already exists, please pick a different name"); redirect = "create_playoff_division.jsp"; } else { final String[] selectedTeams = request.getParameterValues("selected_team"); final List<Integer> teamNumbers = new LinkedList<Integer>(); for (final String teamStr : selectedTeams) { final int num = Integer.parseInt(teamStr); teamNumbers.add(num); } if (LOGGER.isTraceEnabled()) { LOGGER.trace("Selected team numbers: " + teamNumbers); } Playoff.createPlayoffBracket(connection, currentTournamentID, bracketName, teamNumbers); message.append("<p id='success'>Created playoff bracket" + bracketName + "</p>"); redirect = "index.jsp"; } } else { // create bracket based on award group or judging group boolean done = false; Enumeration<String> paramNames = request.getParameterNames(); while (paramNames.hasMoreElements()) { final String paramName = paramNames.nextElement(); if (paramName.startsWith("create_award_group_")) { final String idxStr = paramName.substring("create_award_group_".length()); final int idx = Integer.parseInt(idxStr); final String awardGroup = request.getParameter("award_group_" + idx); // get list of teams in this award group final List<Integer> teamNumbers = new LinkedList<>(); for (final Map.Entry<Integer, TournamentTeam> entry : data.getTournamentTeams().entrySet()) { if (awardGroup.equals(entry.getValue().getAwardGroup())) { teamNumbers.add(entry.getKey()); } } Playoff.createPlayoffBracket(connection, currentTournamentID, awardGroup, teamNumbers); message.append("<p id='success'>Created playoff bracket '" + awardGroup + "'</p>"); redirect = "index.jsp"; done = true; } else if (paramName.startsWith("create_judging_group_")) { final String idxStr = paramName.substring("create_judging_group_".length()); final int idx = Integer.parseInt(idxStr); final String judgingGroup = request.getParameter("judging_group_" + idx); // get list of teams in this judging group final List<Integer> teamNumbers = new LinkedList<>(); for (final Map.Entry<Integer, TournamentTeam> entry : data.getTournamentTeams().entrySet()) { if (judgingGroup.equals(entry.getValue().getJudgingGroup())) { teamNumbers.add(entry.getKey()); } } Playoff.createPlayoffBracket( connection, currentTournamentID, judgingGroup, teamNumbers); message.append("<p id='success'>Created playoff bracket '" + judgingGroup + "'</p>"); redirect = "index.jsp"; done = true; } } if (!done) { message.append("<p class='error'>No action specified</p>"); redirect = "create_playoff_division.jsp"; } } } catch (final SQLException sqle) { message.append( "<p class='error'>Error talking to the database: " + sqle.getMessage() + "</p>"); LOGGER.error(sqle, sqle); throw new RuntimeException("Error talking to the database", sqle); } finally { SQLFunctions.close(connection); } session.setAttribute(SessionAttributes.MESSAGE, message.toString()); response.sendRedirect(response.encodeRedirectURL(redirect)); } }
/** XML utilities for FLL. */ @SuppressFBWarnings( value = {"NM_SAME_SIMPLE_NAME_AS_SUPERCLASS"}, justification = "Intentionally shadowing parent class") public final class XMLUtils extends net.mtu.eggplant.xml.XMLUtils { private static final Logger LOGGER = LogUtils.getLogger(); private XMLUtils() {} /** * Find a subjective category by name. * * @param challengeDocument the document to look in * @param name the name to look for * @return the element or null if one is not found */ public static Element getSubjectiveCategoryByName( final Document challengeDocument, final String name) { for (final Element categoryElement : new NodelistElementCollectionAdapter( challengeDocument.getDocumentElement().getElementsByTagName("subjectiveCategory"))) { final String categoryName = categoryElement.getAttribute("name"); if (categoryName.equals(name)) { return categoryElement; } } return null; } /** * Check if an element describes an enumerated goal or not. * * @param element the goal element * @return if the element represents an enumerated goal */ public static boolean isEnumeratedGoal(final Element element) { if (!"goal".equals(element.getNodeName())) { // not a goal element return false; } final Iterator<Element> values = new NodelistElementCollectionAdapter(element.getElementsByTagName("value")).iterator(); return values.hasNext(); } /** * Check if an element describes a computed goal or not. * * @param element the goal element * @return if the element represents a computed goal */ public static boolean isComputedGoal(final Element element) { return "computedGoal".equals(element.getNodeName()); } /** Get the winner criteria for a particular element. */ public static WinnerType getWinnerCriteria(final Element element) { if (element.hasAttribute("winner")) { final String str = element.getAttribute("winner"); final String sortStr; if (!str.isEmpty()) { sortStr = str.toUpperCase(); } else { sortStr = "HIGH"; } return Enum.valueOf(WinnerType.class, sortStr); } else { return WinnerType.HIGH; } } /** Get the score type for a particular element. */ public static ScoreType getScoreType(final Element element) { if (element.hasAttribute("scoreType")) { final String str = element.getAttribute("scoreType"); final String sortStr; if (!str.isEmpty()) { sortStr = str.toUpperCase(); } else { sortStr = "INTEGER"; } return Enum.valueOf(ScoreType.class, sortStr); } else { return ScoreType.INTEGER; } } /** @see #getDoubleAttributeValue(Element, String) */ public static String getStringAttributeValue(final Element element, final String attributeName) { if (null == element) { return null; } final String str = element.getAttribute(attributeName); return str; } /** @see #getDoubleAttributeValue(Element, String) */ @SuppressFBWarnings( value = {"NP_BOOLEAN_RETURN_NULL"}, justification = "Need to return Null so that we can determine when there is no score") public static Boolean getBooleanAttributeValue( final Element element, final String attributeName) { if (null == element) { return null; } final String str = element.getAttribute(attributeName); if (str.isEmpty()) { return null; } else { return Boolean.valueOf(str); } } /** * Get a double value from an attribute. * * @param element the element to get the attribute from, may be null * @param attributeName the attribute name to get * @return the value, null if element is null or the attribute value is null or empty */ public static Double getDoubleAttributeValue(final Element element, final String attributeName) { if (null == element) { return null; } final String str = element.getAttribute(attributeName); if (str.isEmpty()) { return null; } else { return Double.valueOf(str); } } /** * Compare two documents and check if they are the same or not. * * @param controlDoc * @param testDoc * @return true if the documents have the same elements and attributes, reguardless of order */ public static boolean compareDocuments(final Document controlDoc, final Document testDoc) { final Diff xmldiff = new Diff(controlDoc, testDoc); return xmldiff.similar(); } public static List<String> getSubjectiveCategoryNames(final Document challengeDocument) { final List<String> subjectiveCategories = new LinkedList<String>(); for (final Element categoryElement : new NodelistElementCollectionAdapter( challengeDocument.getDocumentElement().getElementsByTagName("subjectiveCategory"))) { final String categoryName = categoryElement.getAttribute("name"); subjectiveCategories.add(categoryName); } return subjectiveCategories; } public static boolean isValidCategoryName(final Document challengeDocument, final String name) { return getSubjectiveCategoryNames(challengeDocument).contains(name); } /** Get all challenge descriptors build into the software. */ public static Collection<URL> getAllKnownChallengeDescriptorURLs() { final String baseDir = "fll/resources/challenge-descriptors/"; final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); final URL directory = classLoader.getResource(baseDir); if (null == directory) { LOGGER.warn("base dir for challenge descriptors not found"); return Collections.emptyList(); } final Collection<URL> urls = new LinkedList<URL>(); if ("file".equals(directory.getProtocol())) { try { final URI uri = directory.toURI(); final File fileDir = new File(uri); final File[] files = fileDir.listFiles(); if (null != files) { for (final File file : files) { if (file.getName().endsWith(".xml")) { try { final URL fileUrl = file.toURI().toURL(); urls.add(fileUrl); } catch (final MalformedURLException e) { LOGGER.error("Unable to convert file to URL: " + file.getAbsolutePath(), e); } } } } } catch (final URISyntaxException e) { LOGGER.error("Unable to convert URL to URI: " + e.getMessage(), e); } } else if (directory.getProtocol().equals("jar")) { final CodeSource src = XMLUtils.class.getProtectionDomain().getCodeSource(); if (null != src) { final URL jar = src.getLocation(); JarInputStream zip = null; try { zip = new JarInputStream(jar.openStream()); JarEntry ze = null; while ((ze = zip.getNextJarEntry()) != null) { final String entryName = ze.getName(); if (entryName.startsWith(baseDir) && entryName.endsWith(".xml")) { // add 1 to baseDir to skip past the path separator final String challengeName = entryName.substring(baseDir.length()); // check that the file really exists and turn it into a URL final URL challengeUrl = classLoader.getResource(baseDir + challengeName); if (null != challengeUrl) { urls.add(challengeUrl); } else { // TODO could write the resource out to a temporary file if // needed // then mark the file as delete on exit LOGGER.warn( "URL doesn't exist for " + baseDir + challengeName + " entry: " + entryName); } } } zip.close(); } catch (final IOException e) { LOGGER.error("Error reading jar file at: " + jar.toString(), e); } finally { IOUtils.closeQuietly(zip); } } else { LOGGER.warn("Null code source in protection domain, cannot get challenge descriptors"); } } else { throw new UnsupportedOperationException("Cannot list files for URL " + directory); } return urls; } }
/** Generate a schema diagram of our example database. */ public class GenerateDatabaseDiagram { private static final Logger LOGGER = LogUtils.getLogger(); /** @param args */ public static void main(final String[] args) { LogUtils.initializeLogging(); if (args.length != 1) { LOGGER.fatal("You must specify the output directory"); return; } final String dbname = "generate_schema"; Connection connection = null; try { // generate example database final DataSource datasource = Utilities.createMemoryDataSource(dbname); connection = datasource.getConnection(); final String baseDir = "fll/resources/challenge-descriptors/"; final String challengeName = "example-database.xml"; final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); final URL challengeUrl = classLoader.getResource(baseDir + challengeName); final InputStream stream = challengeUrl.openStream(); final Reader reader = new InputStreamReader(stream, Utilities.DEFAULT_CHARSET); final Document document = ChallengeParser.parse(reader); GenerateDB.generateDB(document, connection); SchemaAnalyzer analyzer = new SchemaAnalyzer(); final Config config = new HsqlMemConfig(); config.setAdsEnabled(false); config.setDb(dbname); config.setHighQuality(true); config.setSchema("PUBLIC"); config.setUser("SA"); config.setOutputDir(args[0]); analyzer.analyze(config); } catch (final SQLException e) { LOGGER.fatal("Error talking to the database", e); } catch (final Exception e) { LOGGER.fatal("Error creating the diagram", e); } finally { // clean up database SQLFunctions.close(connection); } } /** Special {@link Config} for handling hsqldb mem. Also turns off the SF logo. */ private static final class HsqlMemConfig extends Config { @Override public String getDbType() { // make sure we are compatible with the existing configurations return "hsqldb"; } @Override public String getHost() { // keeps DbSpecificConfig for hsql happy return "localhost"; } @Override public Properties getDbProperties(final String type) throws IOException, InvalidConfigurationException { final Properties props = super.getDbProperties("hsqldb"); props.setProperty("connectionSpec", "jdbc:hsqldb:mem:<db>"); return props; } /** Always disable the logo. */ @Override public boolean isLogoEnabled() { return false; } } }