/** * Copyright © 2013 enioka. All rights reserved * Authors: Marc-Antoine GOUILLART (marc-antoine.gouillart@enioka.com) * Pierre COPPEE (pierre.coppee@enioka.com) * * 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. */ package com.enioka.jqm.tools; import java.io.File; import java.util.HashMap; import java.util.Map; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.enioka.jqm.jdbc.DbConn; import com.enioka.jqm.jdbc.NoResultException; import com.enioka.jqm.model.Cl; import com.enioka.jqm.model.ClEvent; import com.enioka.jqm.model.ClHandler; import com.enioka.jqm.model.JobDef; import com.enioka.jqm.model.Queue; import com.enioka.jqm.model.JobDef.PathType; class XmlJobDefParser { private static Logger jqmlogger = Logger.getLogger(XmlJobDefParser.class); private XmlJobDefParser() { } /** * Will import all JobDef from an XML file. Creates and commits a transaction. * * @param path * @param cnx * @throws JqmEngineException */ static void parse(String path, DbConn cnx) throws JqmEngineException { // Argument checks jqmlogger.trace(path); if (path == null || path.isEmpty()) { throw new IllegalArgumentException("XML file path cannot be empty"); } if (cnx == null) { throw new IllegalArgumentException("Database connection cannot be null"); } File f = new File(path); if (f == null || !f.isFile() || !f.canRead()) { throw new IllegalArgumentException("The XML file " + f + " was not found or cannot be read."); } // Create parsers DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); dbFactory.setNamespaceAware(true); DocumentBuilder dBuilder; // Result fields Map<String, Integer> createdQueues = new HashMap<String, Integer>(); JobDef jd = null; Integer queueId = null; try { dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(f); // Schema validation SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = factory.newSchema(new File("./lib/res.xsd")); Validator validator = schema.newValidator(); validator.validate(new DOMSource(doc)); doc.getDocumentElement().normalize(); // First parse CLs NodeList clList = doc.getElementsByTagName("context"); for (int clIndex = 0; clIndex < clList.getLength(); clIndex++) { Cl cl; Node clNode = clList.item(clIndex); if (clNode.getNodeType() != Node.ELEMENT_NODE) { continue; } Element clElement = (Element) clNode; String clName = clElement.getElementsByTagName("name").item(0).getTextContent().trim(); try { cl = Cl.select_key(cnx, clName); // Remove all handlers - we will recreate them. cnx.runUpdate("clehprm_delete_all_for_cl", cl.getId()); cnx.runUpdate("cleh_delete_all_for_cl", cl.getId()); } catch (NoResultException e) { Cl.create(cnx, clName, false, null, false, true, null); cl = Cl.select_key(cnx, clName); } // Basic attributes (with defaults) if (clElement.getElementsByTagName("childFirst").getLength() > 0) { cl.setChildFirst(Boolean.parseBoolean(clElement.getElementsByTagName("childFirst").item(0).getTextContent())); } else { cl.setChildFirst(false); } if (clElement.getElementsByTagName("tracingEnabled").getLength() > 0) { cl.setTracingEnabled(Boolean.parseBoolean(clElement.getElementsByTagName("tracingEnabled").item(0).getTextContent())); } else { cl.setTracingEnabled(false); } if (clElement.getElementsByTagName("persistent").getLength() > 0) { cl.setPersistent(Boolean.parseBoolean(clElement.getElementsByTagName("persistent").item(0).getTextContent())); } else { cl.setPersistent(true); } if (clElement.getElementsByTagName("hiddenJavaClasses").getLength() > 0) { cl.setHiddenClasses(clElement.getElementsByTagName("hiddenJavaClasses").item(0).getTextContent().trim()); } else { cl.setHiddenClasses(null); } if (clElement.getElementsByTagName("runners").getLength() > 0) { cl.setAllowedRunners(clElement.getElementsByTagName("runners").item(0).getTextContent().trim()); } else { cl.setAllowedRunners(null); } cl.update(cnx); if (clElement.getElementsByTagName("eventHandlers").getLength() > 0) { NodeList handlersList = ((Element) clElement.getElementsByTagName("eventHandlers").item(0)) .getElementsByTagName("handler"); for (int j = 0; j < handlersList.getLength(); j++) { Element hElement = (Element) handlersList.item(j); Map<String, String> handlerPrms = new HashMap<String, String>(); if (hElement.getElementsByTagName("parameters").getLength() > 0) { NodeList prmList = ((Element) hElement.getElementsByTagName("parameters").item(0)) .getElementsByTagName("parameter"); for (int k = 0; k < prmList.getLength(); k++) { Element prmElement = (Element) prmList.item(k); handlerPrms.put(prmElement.getElementsByTagName("key").item(0).getTextContent(), prmElement.getElementsByTagName("value").item(0).getTextContent()); } } ClHandler.create(cnx, ClEvent.JI_STARTING, hElement.getElementsByTagName("className").item(0).getTextContent().trim(), cl.getId(), handlerPrms); } } } // Second parse jars NodeList jarList = doc.getElementsByTagName("jar"); for (int jarIndex = 0; jarIndex < jarList.getLength(); jarIndex++) { Node jarNode = jarList.item(jarIndex); if (jarNode.getNodeType() != Node.ELEMENT_NODE) { continue; } Element jarElement = (Element) jarNode; NodeList jdList = jarElement.getElementsByTagName("jobDefinition"); for (int jdIndex = 0; jdIndex < jdList.getLength(); jdIndex++) { Element jdElement = (Element) jdList.item(jdIndex); // Retrieve existing JobDef (if exists) String name = jdElement.getElementsByTagName("name").item(0).getTextContent().trim(); try { jd = JobDef.select_key(cnx, name); } catch (NoResultException e) { jd = new JobDef(); } // Retrieve the Queue on which to run the JobDef Queue q = null; try { q = jd.getQueue(cnx); } catch (NoResultException e) { // Nothing. } if (q == null && jdElement.getElementsByTagName("queue").getLength() != 0) { // Specified inside the XML,nothing yet in DB. Does the queue already exist? String qname = jdElement.getElementsByTagName("queue").item(0).getTextContent().trim(); try { queueId = Queue.select_key(cnx, qname).getId(); } catch (NoResultException e) { // The queue must be created. if (createdQueues.containsKey(qname)) { queueId = createdQueues.get(qname); } else { queueId = Queue.create(cnx, qname, "Created from a jobdef import. Description should be set later", false); createdQueues.put(qname, queueId); } } jd.setQueue(queueId); } else if (q == null) { // Not specified (and no queue specified inside DB) => default queue queueId = cnx.runSelectSingle("q_select_default", Integer.class); jd.setQueue(queueId); } // Simple jar attributes jd.setJarPath(jarElement.getElementsByTagName("path").item(0).getTextContent().trim()); jd.setPathType(PathType.valueOf(jarElement.getElementsByTagName("pathType").getLength() > 0 ? jarElement.getElementsByTagName("pathType").item(0).getTextContent().trim() : "FS")); // Simple JD attributes jd.setCanBeRestarted( "true".equals(jdElement.getElementsByTagName("canBeRestarted").item(0).getTextContent().trim()) ? true : false); jd.setJavaClassName(jdElement.getElementsByTagName("javaClassName").item(0).getTextContent().trim()); jd.setDescription(jdElement.getElementsByTagName("description").item(0).getTextContent()); jd.setApplicationName(name); jd.setModule(jdElement.getElementsByTagName("module").item(0).getTextContent()); jd.setHighlander( "true".equals(jdElement.getElementsByTagName("highlander").item(0).getTextContent().trim()) ? true : false); // Classifier if (jdElement.getElementsByTagName("application").getLength() > 0) { jd.setApplication(jdElement.getElementsByTagName("application").item(0).getTextContent()); } else { jd.setApplication(null); } // Keyword used to be called "other". We allow both for ascending compatibility. ("other" is deprecated - don't use) if (jdElement.getElementsByTagName("other1").getLength() > 0) { jd.setKeyword1(jdElement.getElementsByTagName("other1").item(0).getTextContent()); } else { jd.setKeyword1(null); } if (jdElement.getElementsByTagName("keyword1").getLength() > 0) { jd.setKeyword1(jdElement.getElementsByTagName("keyword1").item(0).getTextContent()); } else { jd.setKeyword1(null); } if (jdElement.getElementsByTagName("other2").getLength() > 0) { jd.setKeyword2(jdElement.getElementsByTagName("other2").item(0).getTextContent()); } else { jd.setKeyword2(null); } if (jdElement.getElementsByTagName("keyword2").getLength() > 0) { jd.setKeyword2(jdElement.getElementsByTagName("keyword2").item(0).getTextContent()); } else { jd.setKeyword2(null); } if (jdElement.getElementsByTagName("other3").getLength() > 0) { jd.setKeyword3(jdElement.getElementsByTagName("other3").item(0).getTextContent()); } else { jd.setKeyword3(null); } if (jdElement.getElementsByTagName("keyword3").getLength() > 0) { jd.setKeyword3(jdElement.getElementsByTagName("keyword3").item(0).getTextContent()); } else { jd.setKeyword3(null); } // Class loading if (jdElement.getElementsByTagName("executionContext").getLength() > 0) { String clName = jdElement.getElementsByTagName("executionContext").item(0).getTextContent(); try { jd.setClassLoader(Cl.select_key(cnx, clName).getId()); } catch (NoResultException e) { jqmlogger.fatal("Incorrect deployment descriptor: a job definition is using undefined context " + clName); } } else { jd.setClassLoader(null); } // Alert time if (jdElement.getElementsByTagName("reasonableRuntimeLimitMinute").getLength() > 0) { jd.setMaxTimeRunning( Integer.parseInt(jdElement.getElementsByTagName("reasonableRuntimeLimitMinute").item(0).getTextContent())); } else { jd.setMaxTimeRunning(null); } // Parameters Map<String, String> parameters = new HashMap<String, String>(); NodeList prmList = jdElement.getElementsByTagName("parameter"); for (int prmIndex = 0; prmIndex < prmList.getLength(); prmIndex++) { Element prmElement = (Element) prmList.item(prmIndex); parameters.put(prmElement.getElementsByTagName("key").item(0).getTextContent(), prmElement.getElementsByTagName("value").item(0).getTextContent()); } jd.update(cnx, parameters); jqmlogger.info("Imported application " + jd.getApplicationName()); } } cnx.commit(); } catch (Exception e) { throw new JqmEngineException( "an error occured while parsing the XML file " + path + ". No changes were done to the configuration.", e); } } }