/*==========================================================================*\ | $Id: Semester.java,v 1.3 2012/03/28 13:48:08 stedwar2 Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2006-2012 Virginia Tech | | This file is part of Web-CAT. | | Web-CAT is free software; you can redistribute it and/or modify | it under the terms of the GNU Affero General Public License as published | by the Free Software Foundation; either version 3 of the License, or | (at your option) any later version. | | Web-CAT is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU Affero General Public License | along with Web-CAT; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package org.webcat.core; import com.webobjects.foundation.*; import com.webobjects.eocontrol.*; import java.io.*; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.TimeZone; import org.webcat.core.AuthenticationDomain; import org.webcat.core.Semester; import org.webcat.core._Semester; import org.apache.log4j.*; // ------------------------------------------------------------------------- /** * Represents a single school semester. * * @author Stephen Edwards * @author Last changed by $Author: stedwar2 $ * @version $Revision: 1.3 $, $Date: 2012/03/28 13:48:08 $ */ public class Semester extends _Semester { //~ Constructors .......................................................... // ---------------------------------------------------------- /** * Creates a new Semester object. */ public Semester() { super(); } // ---------------------------------------------------------- /** * A static factory method for creating a new * Semester object given required * attributes and relationships. * @param editingContext The context in which the new object will be * inserted * @param theSeason The semester of the year * @param startDate The start date * @param endDate The end date * @return The newly created object */ public static Semester create( EOEditingContext editingContext, int theSeason, NSTimestamp startDate, NSTimestamp endDate, int startYear ) { Semester result = create(editingContext, startYear); result.setSeason(theSeason); result.setSemesterStartDate(startDate); result.setSemesterEndDate(endDate); return result; } // ---------------------------------------------------------- /** * A static factory method for creating a new * Semester object given required * attributes and relationships. * @param editingContext The context in which the new object will be * inserted * @param theSeason The semester of the year * @param startYear The year for the semester * @param timeZone The time zone for localizing dates, or * null for the system default * @return The newly created object */ public static Semester create( EOEditingContext editingContext, int theSeason, int startYear, TimeZone timeZone ) { return create( editingContext, theSeason, defaultStartingDate(theSeason, startYear, timeZone), defaultEndingDate(theSeason, startYear, timeZone), startYear); } //~ Methods ............................................................... // ---------------------------------------------------------- /** * Returns the "season" portion of a semester name as a string. * * @return The season name as a string */ public String seasonName() { String result = "none"; Number mySeason = season(); if (mySeason != null) { result = names.objectAtIndex(season().intValue()); } return result; } // ---------------------------------------------------------- /** * Set the season by number. * * @param value The season number */ public void setSeason( int value ) { setSeason( integers[value] ); } // ---------------------------------------------------------- /** * Change the value of this object's <code>season</code> * property. * * @param value The new value for this property */ public void setSeason( Integer value ) { if (dirNeedingRenaming == null) { dirNeedingRenaming = dirName(); } super.setSeason(value); } // ---------------------------------------------------------- public Object validateSeason( Object value ) { if ( value == null || value.equals("") || ! (value instanceof Number) ) { throw new ValidationException( "Please provide a season." ); } int ival = ((Number)value).intValue(); if (ival < 0 || ival > WINTER) { throw new ValidationException( "The season must be between 0 and " + WINTER + ", inclusive." ); } return value; } // ---------------------------------------------------------- /** * Change the value of this object's <code>year</code> * property. * * @param value The new value for this property */ public void setYearRaw( Number value ) { if (dirNeedingRenaming == null) { dirNeedingRenaming = dirName(); } takeStoredValueForKey( value, "year" ); } // ---------------------------------------------------------- public void validateForSave() throws ValidationException { super.validateForSave(); // Make sure the season is not a duplicate NSArray<Semester> others = objectsMatchingQualifier(editingContext(), year.is(year()).and(season.is(season()))); if (others.count() > 1 || (others.count() == 1 && others.objectAtIndex(0) != this)) { throw new ValidationException( "Another semester for this season and year already exists." ); } } // ---------------------------------------------------------- /** * Returns the name of this semester as a string. * * @return The semester name as a string */ public String name() { return seasonName() + " " + year(); } // ---------------------------------------------------------- /** * Get a short (no longer than 60 characters) description of this semester, * which currently returns {@link #name()}. * @return the description */ public String userPresentableDescription() { return name(); } // ---------------------------------------------------------- /** * Returns the name of this semester in a form usable as a * subdirectory name. * * @return The semester name as a string */ public String dirName() { return ( seasonName() + year() ).replaceAll( "\\s", "" ); } // ---------------------------------------------------------- @Override public void willUpdate() { java.util.GregorianCalendar now = new java.util.GregorianCalendar(); int thisMonth = now.get(Calendar.MONTH) + 1; if (year() == 0) { setYear(now.get(Calendar.YEAR)); } if (season() == null) { setSeason(defaultSemesterFor(now)); } if (semesterStartDate() == null) { // remember, these months start at 1, while those stored // in "now" start at zero ... int month = defaultStartingMonth( season().intValue() ); int startYear = year(); if (month > thisMonth) { startYear--; } NSTimestamp start = new NSTimestamp( startYear, month, 1, 0, 0, 0, java.util.TimeZone.getDefault() ); if (semesterEndDate() == null || semesterEndDate().after( start )) { setSemesterStartDate(start); } else { setSemesterStartDate(semesterEndDate()); } } if (semesterEndDate() == null) { int month = defaultEndingMonth( season().intValue() ); int endYear = year(); if (month < thisMonth) { endYear++; } NSTimestamp end = new NSTimestamp( endYear, month, 1, 23, 59, 59, java.util.TimeZone.getDefault() ); if (semesterStartDate() == null || semesterStartDate().before(end)) { setSemesterEndDate(end); } else { setSemesterEndDate(semesterStartDate()); } } super.willUpdate(); } // ---------------------------------------------------------- /* (non-Javadoc) * @see er.extensions.eof.ERXGenericRecord#didUpdate() */ public void didUpdate() { super.didUpdate(); if ( dirNeedingRenaming != null ) { renameSubdirs( dirNeedingRenaming, dirName() ); dirNeedingRenaming = null; } } // ---------------------------------------------------------- /** * Guess a semester for a given date. * @param date the date to guess for * @return The semester */ public static int defaultSemesterFor( java.util.Calendar date ) { int month = date.get( java.util.Calendar.MONTH ) + 1; if ( month <= 5 ) return SPRING; else if ( month <= 6 ) return SUMMER1; else if ( month <= 7 ) return SUMMER2; else return FALL; } // ---------------------------------------------------------- /** * Guess the starting month for a semester (assumed to start on day 1). * @param theSeason the semester to guess for * @return The month (starting from 1) */ public static int defaultStartingMonth(int theSeason) { int result = 1; switch (theSeason) { case SUMMER1: result = 6; break; case SUMMER2: result = 7; break; case FALL: result = 8; break; case WINTER: result = 11; break; } return result; } // ---------------------------------------------------------- /** * Guess the starting date for a semester. * @param theSeason the semester to guess for * @param startYear the year in which the semester starts * @param timeZone the time zone to use for localization * @return The starting date, as a time stamp */ public static NSTimestamp defaultStartingDate( int theSeason, int startYear, TimeZone timeZone) { // Note that these month values start at 1, not 0, so they need to // be decremented before being shoved into a calendar object int startMonth = defaultStartingMonth(theSeason); int startDay = 1; Calendar cal = (timeZone == null) ? new GregorianCalendar() : new GregorianCalendar(timeZone); cal.clear(); cal.set(Calendar.YEAR, startYear); cal.set(Calendar.MONTH, startMonth - 1); cal.set(Calendar.DAY_OF_MONTH, startDay); return new NSTimestamp(cal.getTimeInMillis()); } // ---------------------------------------------------------- /** * Guess the ending month for a semester (assumed to end on last day * of the month). * @param theSeason the semester to guess for * @return The month (starting from 1) */ public static int defaultEndingMonth(int theSeason) { int result = 12; switch (theSeason) { case SPRING: result = 5; break; case SUMMER1: result = 6; break; case SUMMER2: result = 7; break; case WINTER: result = 2; break; } return result; } // ---------------------------------------------------------- /** * Guess the ending date for a semester. * @param theSeason the semester to guess for * @param startYear the year in which the semester starts (<b>not</b> ends) * @param timeZone the time zone to use for localization * @return The ending date, as a time stamp */ public static NSTimestamp defaultEndingDate( int theSeason, int startYear, TimeZone timeZone) { // Note that these month values start at 1, not 0, so they need to // be decremented before being shoved into a calendar object int endMonth = defaultEndingMonth(theSeason); int endDay = 30; if (defaultStartingMonth(theSeason) > endMonth) { startYear++; } switch (endMonth) { case 2: endDay = 28; break; case 1: case 3: case 5: case 7: case 8: case 10: case 12: endDay = 31; break; } Calendar cal = (timeZone == null) ? new GregorianCalendar() : new GregorianCalendar(timeZone); cal.clear(); cal.set(Calendar.YEAR, startYear); cal.set(Calendar.MONTH, endMonth - 1); cal.set(Calendar.DAY_OF_MONTH, endDay); return new NSTimestamp(cal.getTimeInMillis()); } //~ Private Methods ....................................................... // ---------------------------------------------------------- private void renameSubdirs(String oldSubdir, String newSubdir) { NSArray<AuthenticationDomain> domains = AuthenticationDomain.authDomains(); String msgs = null; for (AuthenticationDomain domain : domains) { StringBuffer dir = domain.submissionBaseDirBuffer(); dir.append('/'); int baseDirLen = dir.length(); dir.append(oldSubdir); File oldDir = new File(dir.toString()); log.debug("Checking for: " + oldDir); if (oldDir.exists()) { dir.delete(baseDirLen, dir.length()); dir.append(newSubdir); File newDir = new File(dir.toString()); log.debug("Renaming: " + oldDir + " => " + newDir); if (!oldDir.renameTo(newDir)) { msgs = (msgs == null ? "" : (msgs + " ")) + "Failed to rename directory: " + oldDir + " => " + newDir; } } } if (msgs != null) { throw new RuntimeException(msgs); } } //~ Instance/static variables ............................................. public static final int SPRING = 0; public static final int SUMMER1 = 1; public static final int SUMMER2 = 2; public static final int FALL = 3; public static final int WINTER = 4; // For quarters instead of semesters public static final Integer[] integers = { new Integer( SPRING ), new Integer( SUMMER1 ), new Integer( SUMMER2 ), new Integer( FALL ), new Integer( WINTER ) }; public static final NSArray<Integer> integersInNS = new NSArray<Integer>(integers); public static final NSArray<String> names = new NSArray<String>( new String[] { "Spring", "Summer I", "Summer II", "Fall", "Winter" }); private String dirNeedingRenaming = null; static Logger log = Logger.getLogger( Semester.class ); }