| /* $Id: ScheduleManager.java 988245 2010-08-23 18:39:35Z kwright $ */ |
| |
| /** |
| * 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.manifoldcf.crawler.jobs; |
| |
| import org.apache.manifoldcf.core.interfaces.*; |
| import org.apache.manifoldcf.agents.interfaces.*; |
| import org.apache.manifoldcf.crawler.interfaces.*; |
| import java.util.*; |
| |
| /** This class manages the "schedules" table, which contains the automatic execution schedule for each job. |
| * It's separated from the main jobs table because we will need multiple timeslots per job. |
| * |
| * <br><br> |
| * <b>schedules</b> |
| * <table border="1" cellpadding="3" cellspacing="0"> |
| * <tr class="TableHeadingColor"> |
| * <th>Field</th><th>Type</th><th>Description </th> |
| * <tr><td>ownerid</td><td>BIGINT</td><td>Reference:jobs.id</td></tr> |
| * <tr><td>ordinal</td><td>BIGINT</td><td></td></tr> |
| * <tr><td>dayofweek</td><td>VARCHAR(255)</td><td></td></tr> |
| * <tr><td>dayofmonth</td><td>VARCHAR(255)</td><td></td></tr> |
| * <tr><td>monthofyear</td><td>VARCHAR(255)</td><td></td></tr> |
| * <tr><td>yearlist</td><td>VARCHAR(255)</td><td></td></tr> |
| * <tr><td>hourofday</td><td>VARCHAR(255)</td><td></td></tr> |
| * <tr><td>minutesofhour</td><td>VARCHAR(255)</td><td></td></tr> |
| * <tr><td>timezone</td><td>VARCHAR(32)</td><td></td></tr> |
| * <tr><td>windowlength</td><td>BIGINT</td><td></td></tr> |
| * <tr><td>requestminimum</td><td>CHAR(1)</td><td></td></tr> |
| * </table> |
| * <br><br> |
| * |
| */ |
| public class ScheduleManager extends org.apache.manifoldcf.core.database.BaseTable |
| { |
| public static final String _rcsid = "@(#)$Id: ScheduleManager.java 988245 2010-08-23 18:39:35Z kwright $"; |
| |
| // Schema |
| public final static String ownerIDField = "ownerid"; |
| public final static String ordinalField = "ordinal"; |
| public final static String dayOfWeekField = "dayofweek"; |
| public final static String dayOfMonthField = "dayofmonth"; |
| public final static String monthOfYearField = "monthofyear"; |
| public final static String yearField = "yearlist"; |
| public final static String hourOfDayField = "hourofday"; |
| public final static String minutesOfHourField = "minutesofhour"; |
| public final static String timezoneField = "timezone"; |
| public final static String windowDurationField = "windowlength"; |
| public final static String requestMinimumField = "requestminimum"; |
| |
| /** Constructor. |
| *@param threadContext is the thread context. |
| *@param database is the database instance. |
| */ |
| public ScheduleManager(IThreadContext threadContext, IDBInterface database) |
| throws ManifoldCFException |
| { |
| super(database,"schedules"); |
| } |
| |
| /** Install or upgrade. |
| *@param ownerTable is the name of the table that owns this one. |
| *@param owningTablePrimaryKey is the primary key of the owning table. |
| */ |
| public void install(String ownerTable, String owningTablePrimaryKey) |
| throws ManifoldCFException |
| { |
| // Standard practice: Outer loop to support upgrades |
| while (true) |
| { |
| Map existing = getTableSchema(null,null); |
| if (existing == null) |
| { |
| HashMap map = new HashMap(); |
| map.put(ownerIDField,new ColumnDescription("BIGINT",false,false,ownerTable,owningTablePrimaryKey,false)); |
| map.put(ordinalField,new ColumnDescription("BIGINT",false,false,null,null,false)); |
| map.put(dayOfWeekField,new ColumnDescription("VARCHAR(255)",false,true,null,null,false)); |
| map.put(dayOfMonthField,new ColumnDescription("VARCHAR(255)",false,true,null,null,false)); |
| map.put(monthOfYearField,new ColumnDescription("VARCHAR(255)",false,true,null,null,false)); |
| map.put(yearField,new ColumnDescription("VARCHAR(255)",false,true,null,null,false)); |
| map.put(hourOfDayField,new ColumnDescription("VARCHAR(255)",false,true,null,null,false)); |
| map.put(minutesOfHourField,new ColumnDescription("VARCHAR(255)",false,true,null,null,false)); |
| map.put(timezoneField,new ColumnDescription("VARCHAR(32)",false,true,null,null,false)); |
| map.put(windowDurationField,new ColumnDescription("BIGINT",false,true,null,null,false)); |
| map.put(requestMinimumField,new ColumnDescription("CHAR(1)",false,true,null,null,false)); |
| performCreate(map,null); |
| } |
| else |
| { |
| // Upgrade code goes here, if needed. |
| if (existing.get(yearField) == null) |
| { |
| // Need to rename the "year" column as the "yearlist" column. |
| HashMap map = new HashMap(); |
| map.put(yearField,new ColumnDescription("VARCHAR(255)",false,true,null,null,false)); |
| performAlter(map,null,null,null); |
| performModification("UPDATE "+getTableName()+" SET "+yearField+"=year",null,null); |
| ArrayList list = new ArrayList(); |
| list.add("year"); |
| performAlter(null,null,list,null); |
| |
| } |
| |
| if (existing.get(requestMinimumField) == null) |
| { |
| HashMap map = new HashMap(); |
| map.put(requestMinimumField,new ColumnDescription("CHAR(1)",false,true,null,null,false)); |
| performAlter(map,null,null,null); |
| } |
| |
| } |
| |
| // Index management |
| IndexDescription ownerIndex = new IndexDescription(false,new String[]{ownerIDField}); |
| |
| // Get rid of indexes that shouldn't be there |
| Map indexes = getTableIndexes(null,null); |
| Iterator iter = indexes.keySet().iterator(); |
| while (iter.hasNext()) |
| { |
| String indexName = (String)iter.next(); |
| IndexDescription id = (IndexDescription)indexes.get(indexName); |
| |
| if (ownerIndex != null && id.equals(ownerIndex)) |
| ownerIndex = null; |
| else if (indexName.indexOf("_pkey") == -1) |
| // This index shouldn't be here; drop it |
| performRemoveIndex(indexName); |
| } |
| |
| // Add the ones we didn't find |
| if (ownerIndex != null) |
| performAddIndex(null,ownerIndex); |
| |
| break; |
| } |
| } |
| |
| /** Uninstall. |
| */ |
| public void deinstall() |
| throws ManifoldCFException |
| { |
| performDrop(null); |
| } |
| |
| /** Fill in a set of schedules corresponding to a set of owner id's. |
| *@param returnValues is a map keyed by ownerID, with value of JobDescription. |
| *@param ownerIDList is the list of owner id's. |
| *@param ownerIDParams is the corresponding set of owner id parameters. |
| */ |
| public void getRows(Map returnValues, String ownerIDList, ArrayList ownerIDParams) |
| throws ManifoldCFException |
| { |
| IResultSet set = performQuery("SELECT * FROM "+getTableName()+" WHERE "+ownerIDField+" IN ("+ownerIDList+") ORDER BY "+ordinalField+" ASC",ownerIDParams, |
| null,null); |
| int i = 0; |
| while (i < set.getRowCount()) |
| { |
| IResultRow row = set.getRow(i); |
| Long ownerID = (Long)row.getValue(ownerIDField); |
| ScheduleRecord sr = new ScheduleRecord(stringToEnumeratedValue((String)row.getValue(dayOfWeekField)), |
| stringToEnumeratedValue((String)row.getValue(monthOfYearField)), |
| stringToEnumeratedValue((String)row.getValue(dayOfMonthField)), |
| stringToEnumeratedValue((String)row.getValue(yearField)), |
| stringToEnumeratedValue((String)row.getValue(hourOfDayField)), |
| stringToEnumeratedValue((String)row.getValue(minutesOfHourField)), |
| (String)row.getValue(timezoneField), |
| (Long)row.getValue(windowDurationField), |
| stringToRequestMinimumValue((String)row.getValue(requestMinimumField))); |
| ((JobDescription)returnValues.get(ownerID)).addScheduleRecord(sr); |
| i++; |
| } |
| } |
| |
| /** Get the max clauses that can be used with getRowsAlternate. |
| */ |
| public int maxClauseGetRowsAlternate() |
| { |
| return findConjunctionClauseMax(new ClauseDescription[]{}); |
| } |
| |
| /** Fill in a set of schedules corresponding to a set of owner id's. |
| *@param returnValues is a map keyed by ownerID, with a value that is an ArrayList of ScheduleRecord objects. |
| *@param ownerIDParams is the corresponding set of owner id parameters. |
| */ |
| public void getRowsAlternate(Map returnValues, ArrayList ownerIDParams) |
| throws ManifoldCFException |
| { |
| ArrayList list = new ArrayList(); |
| String query = buildConjunctionClause(list,new ClauseDescription[]{ |
| new MultiClause(ownerIDField,ownerIDParams)}); |
| |
| IResultSet set = performQuery("SELECT * FROM "+getTableName()+" WHERE "+query+" ORDER BY "+ordinalField+" ASC",list, |
| null,null); |
| int i = 0; |
| while (i < set.getRowCount()) |
| { |
| IResultRow row = set.getRow(i); |
| Long ownerID = (Long)row.getValue(ownerIDField); |
| ScheduleRecord sr = new ScheduleRecord(stringToEnumeratedValue((String)row.getValue(dayOfWeekField)), |
| stringToEnumeratedValue((String)row.getValue(monthOfYearField)), |
| stringToEnumeratedValue((String)row.getValue(dayOfMonthField)), |
| stringToEnumeratedValue((String)row.getValue(yearField)), |
| stringToEnumeratedValue((String)row.getValue(hourOfDayField)), |
| stringToEnumeratedValue((String)row.getValue(minutesOfHourField)), |
| (String)row.getValue(timezoneField), |
| (Long)row.getValue(windowDurationField), |
| stringToRequestMinimumValue((String)row.getValue(requestMinimumField))); |
| ArrayList theList = (ArrayList)returnValues.get(ownerID); |
| if (theList == null) |
| { |
| theList = new ArrayList(); |
| returnValues.put(ownerID,theList); |
| } |
| theList.add(sr); |
| i++; |
| } |
| } |
| |
| /** Write a schedule list into the database. |
| *@param ownerID is the owning identifier. |
| *@param list is the job description that is the source of the schedule. |
| */ |
| public void writeRows(Long ownerID, IJobDescription list) |
| throws ManifoldCFException |
| { |
| beginTransaction(); |
| try |
| { |
| int i = 0; |
| HashMap map = new HashMap(); |
| while (i < list.getScheduleRecordCount()) |
| { |
| ScheduleRecord record = list.getScheduleRecord(i); |
| map.clear(); |
| map.put(dayOfWeekField,enumeratedValueToString(record.getDayOfWeek())); |
| map.put(monthOfYearField,enumeratedValueToString(record.getMonthOfYear())); |
| map.put(dayOfMonthField,enumeratedValueToString(record.getDayOfMonth())); |
| map.put(yearField,enumeratedValueToString(record.getYear())); |
| map.put(hourOfDayField,enumeratedValueToString(record.getHourOfDay())); |
| map.put(minutesOfHourField,enumeratedValueToString(record.getMinutesOfHour())); |
| map.put(timezoneField,record.getTimezone()); |
| map.put(windowDurationField,record.getDuration()); |
| map.put(requestMinimumField,requestMinimumValueToString(record.getRequestMinimum())); |
| map.put(ownerIDField,ownerID); |
| map.put(ordinalField,new Long((long)i)); |
| performInsert(map,null); |
| i++; |
| } |
| } |
| catch (ManifoldCFException e) |
| { |
| signalRollback(); |
| throw e; |
| } |
| catch (Error e) |
| { |
| signalRollback(); |
| throw e; |
| } |
| finally |
| { |
| endTransaction(); |
| } |
| } |
| |
| /** Delete rows. |
| *@param ownerID is the owner whose rows to delete. |
| */ |
| public void deleteRows(Long ownerID) |
| throws ManifoldCFException |
| { |
| ArrayList list = new ArrayList(); |
| String query = buildConjunctionClause(list,new ClauseDescription[]{ |
| new UnitaryClause(ownerIDField,ownerID)}); |
| |
| performDelete("WHERE "+query,list,null); |
| } |
| |
| /** Go from string to enumerated value. |
| *@param value is the input. |
| *@return the enumerated value. |
| */ |
| public static EnumeratedValues stringToEnumeratedValue(String value) |
| throws ManifoldCFException |
| { |
| if (value == null) |
| return null; |
| try |
| { |
| ArrayList valStore = new ArrayList(); |
| if (!value.equals("*")) |
| { |
| int curpos = 0; |
| while (true) |
| { |
| int newpos = value.indexOf(",",curpos); |
| if (newpos == -1) |
| { |
| valStore.add(new Integer(value.substring(curpos))); |
| break; |
| } |
| valStore.add(new Integer(value.substring(curpos,newpos))); |
| curpos = newpos+1; |
| } |
| } |
| return new EnumeratedValues(valStore); |
| } |
| catch (NumberFormatException e) |
| { |
| throw new ManifoldCFException("Bad number: '"+value+"'",e); |
| } |
| |
| } |
| |
| /** Go from enumerated value to string. |
| *@param values is the enumerated value. |
| *@return the string value. |
| */ |
| public static String enumeratedValueToString(EnumeratedValues values) |
| { |
| if (values == null) |
| return null; |
| if (values.size() == 0) |
| return "*"; |
| StringBuilder rval = new StringBuilder(); |
| Iterator iter = values.getValues(); |
| boolean first = true; |
| while (iter.hasNext()) |
| { |
| if (first) |
| first = false; |
| else |
| rval.append(','); |
| rval.append(((Integer)iter.next()).toString()); |
| } |
| return rval.toString(); |
| } |
| |
| public static String requestMinimumValueToString(boolean requestMinimum) |
| { |
| return requestMinimum?"T":"F"; |
| } |
| |
| public static boolean stringToRequestMinimumValue(String requestMinimum) |
| throws ManifoldCFException |
| { |
| if (requestMinimum == null) |
| return false; |
| else if (requestMinimum.equals("T")) |
| return true; |
| else if (requestMinimum.equals("F")) |
| return false; |
| else |
| throw new ManifoldCFException("Bad requestminimum value: '"+requestMinimum+"'"); |
| } |
| |
| } |