Java tutorial
/** * Copyright (C) 2014 BigLoupe http://bigloupe.github.io/SoS-JobScheduler/ * * Licensed 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 */ /********************************************************* begin of preamble ** ** Copyright (C) 2003-2012 Software- und Organisations-Service GmbH. ** All rights reserved. ** ** This file may be used under the terms of either the ** ** GNU General Public License version 2.0 (GPL) ** ** as published by the Free Software Foundation ** http://www.gnu.org/licenses/gpl-2.0.txt and appearing in the file ** LICENSE.GPL included in the packaging of this file. ** ** or the ** ** Agreement for Purchase and Licensing ** ** as offered by Software- und Organisations-Service GmbH ** in the respective terms of supply that ship with this file. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ** IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS ** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ** POSSIBILITY OF SUCH DAMAGE. ********************************************************** end of preamble*/ package com.sos.jobnet.creator; import com.sos.JSHelper.Basics.JSToolBox; import com.sos.JSHelper.Exceptions.JobSchedulerException; import com.sos.jobnet.classes.JobNetConstants; import com.sos.jobnet.classes.JobNetException; import com.sos.jobnet.db.*; import com.sos.jobnet.options.JobNetCreatorOptions; import com.sos.localization.Messages; import com.sos.scheduler.model.SchedulerObjectFactory; import com.sos.scheduler.model.objects.JSObjOrder; import com.sos.scheduler.model.objects.JSObjRunTime; import org.apache.log4j.Logger; import org.joda.time.DateTime; import org.joda.time.Interval; import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import java.io.File; import java.util.Date; import java.util.List; /** * \file FrequencyChecker.java * \brief check all nodes with state "not_processed" to decide if a node should run or not * * \class FrequencyChecker * \brief check all nodes with state "not_processed" to decide if a node should run or not * * \details * This class is reading all nodes of jobnets are not processed. For each node which is not a bootstrap order the class * decides if it should be processed or not. The decission is based on the runtime defintion for each node. If no runtime * definiton found for a node it will be processed anyway, that means the node in the database will not changed. * * If a node has a runtime defintion it is necessary that the runtime is defined for the same day as the bootstrap order. Otherwise * the node will marked with "isRunnerSkipped" in the database record of the jobnet plan. * * It is not neccessary that the runtime defintion of a node has a period elements, e.g. * <run_time let_run="no"> * <monthdays> * <day day="20"/> * </monthdays> * </run_time> * is a valid run_time defintion for a jobnet node. * * The following run_time elements will be supported: * - monthdays/day * - monthdays/weekday * - weekdays/day * - ultimos/day * - period - that means every day * - date * * \code \endcode * * \author Stefan Schaedlich * \version 1.0 - 20.03.2012 14:29:20 */ public class FrequencyChecker { private final static Logger logger = Logger.getLogger(FrequencyChecker.class); private final static Logger testLogger = Logger.getLogger("frequencyCheckerTest"); private final static DateTimeFormatter fmtDate = DateTimeFormat.forPattern("yyyy-MM-dd"); private final static DateTimeFormatter fmtDateTime = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); private static final Messages msg = new JSToolBox(JobNetConstants.strBundleBaseName).getMessageObject(); private final static String JOBNETCH_D_0001 = "JOBNETCH_D_0001"; // searching for start times of job net nodes from %1$s to %2$s private final static String JOBNETCH_D_0002 = "JOBNETCH_D_0002"; // bootstrap order has node id %2$s. // private final static String JOBNETCH_D_0003 = "JOBNETCH_D_0003"; // searching for starts at %2$s. private final static String JOBNETCH_D_0004 = "JOBNETCH_D_0004"; // the jobnet contains %1$s nodes. private final static String JOBNETCH_D_0008 = "JOBNETCH_D_0008"; // start time: %1$s. private final static String JOBNETCH_I_0001 = "JOBNETCH_I_0001"; // processing jobnet with id %1$s. private final static String JOBNETCH_I_0002 = "JOBNETCH_I_0002"; // order %1$s (node id %2$s) is already skipped. private final static String JOBNETCH_I_0003 = "JOBNETCH_I_0003"; // order %1$s (node id %2$s) has next start time for %3$s and will be skipped. private final static String JOBNETCH_I_0004 = "JOBNETCH_I_0004"; // order %1$s (node id %2$s) has no start time and will be NOT skipped. private final static String JOBNETCH_I_0005 = "JOBNETCH_I_0005"; // order %1$s (node id %2$s) has a start time for %3$s and will NOT skipped. private final static String JOBNETCH_I_0006 = "JOBNETCH_I_0006"; // order %1$s (node id %2$s) has to be started on demand. private final static String JOBNETCH_E_0001 = "JOBNETCH_E_0001"; // bootstrap order has no single_start private final static String JOBNETCH_E_0002 = "JOBNETCH_E_0002"; // no jobnet found for UUID %1$s. private final static String JOBNETCH_E_0003 = "JOBNETCH_E_0003"; // job net node with id $1%s not found. private final ObjectModelConnector connection; private final JobNetPlanDBLayer planDbLayer; private final JobNetNodeDBLayer nodeDbLayer; private final SchedulerObjectFactory factory; public FrequencyChecker(JobNetCreatorOptions options) { this.connection = ObjectModelConnector.getInstance(options.SCHEDULER_HOST, options.SCHEDULER_TCP_PORT, options.SCHEDULER_CONFIGURATION_DIRECTORY); this.factory = connection.getFactory(); File configFile = new File(options.hibernate_connection_config_file.Value()); this.planDbLayer = new JobNetPlanDBLayer(configFile, options.SCHEDULER_ID.Value()); this.nodeDbLayer = new JobNetNodeDBLayer(configFile, options.SCHEDULER_ID.Value()); } public void processJobNet(JobNetPlanDBItem bootstrapOrder) { String uuid = bootstrapOrder.getUuid(); logger.info(msg.getMsg(JOBNETCH_I_0001, uuid)); // processing jobnet with id %1$s. logger.debug(msg.getMsg(JOBNETCH_D_0002, bootstrapOrder.getNodeId())); // bootstrap order has node id %2$s. Date d = bootstrapOrder.getPlannedStartTime(); if (d == null) { String msgText = msg.getMsg(JOBNETCH_E_0001); // bootstrap order has no single_start logger.error(msgText); throw new JobNetException(msgText); } DateTime from = new DateTime(d); from = from.minusMillis(from.getMillisOfDay()); DateTime to = from.plusDays(1); Interval baseInterval = new Interval(from, to); logger.debug(msg.getMsg(JOBNETCH_D_0001, fmtDateTime.print(from), fmtDateTime.print(to))); // searching for start times of job net nodes from %1$s to %2$s LocalDate forDay = new LocalDate(from); // logger.debug(msg.getMsg(JOBNETCH_D_0003,fmtDate.print(baseInterval.getStart()))); // searching for starts at %2$s. List<JobNetPlanDBItem> jobnetOrders = getJobnet(uuid); if (jobnetOrders == null) { String msgText = msg.getMsg(JOBNETCH_E_0002, uuid); logger.error(msgText); // no jobnet found for UUID %1$s. throw new JobSchedulerException(msgText); } logger.debug(msg.getMsg(JOBNETCH_D_0004, jobnetOrders.size())); // the jobnet contains %1$s nodes. factory.setUseDefaultPeriod(true); // allows the use of runtime elements without or with incomplete periods planDbLayer.beginTransaction(); for (JobNetPlanDBItem currentOrder : jobnetOrders) { JobNetNodeDBItem currentNode = getJobNetNode(currentOrder.getNodeId()); if (!currentOrder.getBootstrap()) { // the properties for the bootstrap order has to be set in JobNetPlanCreator if (currentOrder.getIsRunnerSkipped()) { logger.info(msg.getMsg(JOBNETCH_I_0002, currentNode.getNode(), currentOrder.getNodeId())); // order %1$s (node id %2$s) is already skipped. } else { JSObjOrder jsOrder = getJSObjOrder(currentOrder.getOrderXml()); JSObjRunTime runTime = jsOrder.getJSObjRunTime(); if (runTime.hasSubsequentRunTimes()) { LocalDate startDay = getNextStartDayInIntervalOrNull(runTime, baseInterval); if (startDay == null) { currentOrder.setIsRunnerSkipped(true); // order %1$s (node id %2$s) has no start time for %3$s and will be skipped. logger.info(msg.getMsg(JOBNETCH_I_0003, currentNode.getNode(), currentOrder.getNodeId(), fmtDate.print(forDay))); } else { // order %1$s (node id %2$s) has a start time for %3$s and will NOT skipped. logger.debug(msg.getMsg(JOBNETCH_I_0005, currentNode.getNode(), currentOrder.getNodeId(), fmtDate.print(forDay))); if (currentOrder.getIsRunnerOnDemand()) { // order %1$s (node id %2$s) has to be started on demand. logger.info(msg.getMsg(JOBNETCH_I_0006, currentNode.getNode(), currentOrder.getNodeId())); currentOrder.setIsRunnerOnDemand(true); } } } else { if (currentOrder.getIsRunnerOnDemand()) { // order %1$s (node id %2$s) has no start time and will be NOT skipped. currentOrder.setIsRunnerOnDemand(true); logger.info( msg.getMsg(JOBNETCH_I_0004, currentNode.getNode(), currentOrder.getNodeId())); } else { logger.debug( "nothing to do - order has neither a start_time nor the parameter on_demand."); } } logger.debug(currentOrder.getOrderXml().replace("\n", "")); planDbLayer.update(currentOrder); } } logRecord(currentNode, currentOrder); } planDbLayer.commit(); } private JobNetNodeDBItem getJobNetNode(long nodeId) { JobNetNodeFilter filter = new JobNetNodeFilter(); filter.setNodeId(nodeId); nodeDbLayer.setFilter(filter); List<JobNetNodeDBItem> result = nodeDbLayer.getJobnetNodeList(0); if (result == null || result.size() == 0) { String msgText = msg.getMsg(JOBNETCH_E_0003, nodeId); logger.error(msgText); // job net node with id $1%s not found. throw new JobNetException(msgText); } return result.get(0); } /** * \brief gets a list of all jobnodes for a single jobnet indenticated with uuid * @param uuid * @return */ private List<JobNetPlanDBItem> getJobnet(String uuid) { JobNetPlanFilter filter = new JobNetPlanFilter(); filter.setUuid(uuid); planDbLayer.setFilter(filter); return planDbLayer.getJobnetPlanList(0); } /** * \brief get the next single start for an order * @return */ private LocalDate getNextStartDayInIntervalOrNull(JSObjRunTime runTime, Interval forDay) { List<DateTime> startTimes = runTime.getDtSingleStarts(forDay); for (DateTime start : startTimes) { logger.debug(msg.getMsg(JOBNETCH_D_0008, fmtDateTime.print(start))); // start time: %1$s. } return (startTimes.size() == 0) ? null : new LocalDate(startTimes.get(0)); } /** * \brief gets a order object for an order given by xml * @param orderXml * @return */ private JSObjOrder getJSObjOrder(String orderXml) { JSObjOrder order = new JSObjOrder(factory); return order.getOrderFromXMLString(orderXml); } private void logRecord(JobNetNodeDBItem node, JobNetPlanDBItem record) { String message = node.getNode() + ";skipped=" + record.getIsRunnerSkipped().toString() + ";ondemand=" + record.getIsRunnerOnDemand().toString(); testLogger.debug(message); } }