Java tutorial
/** JEM, the BEE - Job Entry Manager, the Batch Execution Environment Copyright (C) 2012-2015 Andrea "Stock" Stocchero This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program 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 General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.pepstock.jem.ant; import java.io.IOException; import java.io.StringReader; import java.util.List; import java.util.Properties; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.pepstock.jem.Jcl; import org.pepstock.jem.ant.tasks.DataDescription; import org.pepstock.jem.ant.tasks.DataSet; import org.pepstock.jem.ant.tasks.Lock; import org.pepstock.jem.ant.tasks.ValueParser; import org.pepstock.jem.factories.JclFactoryException; /** * Is a JCL factory which enables to submit a script directly, withou having any ANT file.<br> * It creates a ANT file at runtime, adding the content of script inside ANT file.<br/> * The elements (begin and end ones) MUST alone on comment line.<br/> * <br/> * Example:<br/> * <pre> * # <JEM-xxx> * # key=value * # </JEM-xxx> * </pre> * * @author Andrea "Stock" Stocchero * @version 2.2 */ public abstract class ScriptFactory extends AntFactory { private static final long serialVersionUID = 1L; /** * Returns the mime type of script language * @return the mime type of script language */ public abstract String getMode(); /** * TAG element to put on comments of script which defines the start point of JEM meta data. * @return TAG element to put on comments of script which defines the start point of JEM meta data */ public abstract String getBeginElement(); /** * TAG element to put on comments of script which defines the end point of JEM meta data. * @return TAG element to put on comments of script which defines the end point of JEM meta data */ public abstract String getEndElement(); /** * Char sequence defined in script language as comment * @return Char sequence defined in script language as comment */ public abstract String getCommentCharSequence(); /** * Returns the ANT task to use to execute the script. * @return the ANT task to use to execute the script */ public abstract Class<?> getAntTask(); /* (non-Javadoc) * @see org.pepstock.jem.ant.AntFactory#createJcl(java.lang.String) */ @Override public final Jcl createJcl(String content) throws JclFactoryException { StringBuilder result = null; try { // reads script extracting the JEM properties Properties jemProperties = getProperties(content); // creates ANT file result = getAntJcl(content, jemProperties); } catch (Exception e) { throw new JclFactoryException(e.getMessage(), e); } Jcl jcl; try { // used ANTJcl to create the JCL jcl = super.createJcl(result.toString()); } catch (JclFactoryException e) { // At this time type=ANT and it's not correct // so overrides the new type e.getJcl().setType(getType()); // sets JCL mode e.getJcl().setMode(getMode()); throw e; } // overrides the content JCL, putting ANT language jcl.setContentToBeExecuted(result.toString()); // sets the original script as content jcl.setContent(content); // sets JCL mode jcl.setMode(getMode()); return jcl; } /** * Reads the script extracting the meta data for JEM. * * @param content script content * @return a lit of properties with JEM properties * @throws Exception if any error occurs */ private Properties getProperties(String content) throws JclFactoryException, IOException { Properties jemProperties = new Properties(); // flag to check if it's inside of meta data reading boolean isInJemConfig = false; // if it's able to parse this script // It's difficult to validate a script. All is based on different // tags used in the comments boolean isScript = false; StringBuilder propertiesStrings = new StringBuilder(); // reads script StringReader contentReader = new StringReader(content); List<String> lines = IOUtils.readLines(contentReader); // scans lines for (String line : lines) { // if is a comment if (StringUtils.startsWithIgnoreCase(line, getCommentCharSequence())) { // removes the first part and trim spaces String postComment = StringUtils.stripStart(line, getCommentCharSequence()).trim(); // checks if is the begin element if (getBeginElement().equalsIgnoreCase(postComment)) { // if flag is true, means the begin element is written twice if (isInJemConfig) { throw new JclFactoryException( AntMessage.JEMA070E.toMessage().getFormattedMessage(getBeginElement())); } // sets flags isInJemConfig = true; isScript = true; } else if (getEndElement().equalsIgnoreCase(postComment)) { // checks if is the end element // if the flag is false, means that there isn't begin element if (!isInJemConfig) { throw new JclFactoryException( AntMessage.JEMA071E.toMessage().getFormattedMessage(getBeginElement())); } // sets false and break isInJemConfig = false; break; } else if (isInJemConfig) { //reads properties if flag is true propertiesStrings.append(postComment).append(System.getProperty("line.separator")); } } else if (isInJemConfig) { // if we are here. that means the comment line stops before closing the metadata throw new JclFactoryException(AntMessage.JEMA071E.toMessage().getFormattedMessage(getEndElement())); } } // if we are here, that means it gets the end before closing the metadata if (isInJemConfig) { throw new JclFactoryException(AntMessage.JEMA071E.toMessage().getFormattedMessage(getEndElement())); } // if we are here, there isn't the begin element and then the script is not of the type of the factory if (!isScript) { throw new JclFactoryException(AntMessage.JEMA071E.toMessage().getFormattedMessage(getBeginElement())); } // loads properties StringReader reader = new StringReader(propertiesStrings.toString()); jemProperties.load(reader); return jemProperties; } /** * Creates a ANT file to execute the script * @param content script content * @param jemProperties all JEM properties read from script comment * @return a string with ANT file * @throws AntException */ private StringBuilder getAntJcl(String content, Properties jemProperties) throws AntException { StringBuilder resultDD = new StringBuilder(); StringBuilder result = new StringBuilder(); result.append("<?xml version=\"1.0\"?>"); result.append("<project default=\"exec\" basedir=\".\">"); // loads all jem properties for (Object key : jemProperties.keySet()) { String value = jemProperties.getProperty(key.toString()); if (key.toString().startsWith(AntKeys.ANT_DATA_DESCRIPTION_PREFIX)) { resultDD.append(createDataDescription(key.toString(), value)); } else if (key.toString().equalsIgnoreCase(AntKeys.ANT_LOCK_KEY)) { resultDD.append(createLocks(value)); } else { result.append("<property name=\"" + key.toString() + "\" value=\"" + value + "\"/>"); } } // sets the ANT task which will execute the script result.append("<taskdef name=\"script\" classname=\"" + getAntTask().getName() + "\" />"); result.append("<target name=\"exec\">"); // writes all script result.append("<script><![CDATA["); result.append(content); result.append("]]>"); result.append(resultDD); result.append("</script>"); result.append("</target>"); result.append("</project>"); return result; } /** * * @param key * @param value * @return * @throws AntException */ private String createDataDescription(String key, String value) throws AntException { String ddName = StringUtils.substringAfter(key, AntKeys.ANT_DATA_DESCRIPTION_PREFIX); if (ddName == null || ddName.trim().length() == 0) { throw new AntException(AntMessage.JEMA005E); } DataDescription dd = new DataDescription(); dd.setName(ddName.trim()); ValueParser.loadDataDescription(dd, value); if (dd.isMultiDataset()) { throw new AntException(AntMessage.JEMA006E, dd.getName(), dd.getDisposition()); } StringBuilder sb = new StringBuilder(); sb.append("<dataDescription"); sb.append(" name=\"").append(dd.getName()).append("\" "); if (dd.isSysout()) { sb.append(" disposition=\"NEW\">"); sb.append(" sysout=\"true\"/>"); } else { sb.append(" disposition=\"").append(dd.getDisposition()).append("\">"); if (!dd.getDatasets().isEmpty()) { DataSet ds = dd.getDatasets().get(0); sb.append("<dataSet"); if (ds.isInline()) { sb.append(">").append(ds.getText().toString()).append("</dataSet>"); } else { if (ds.isGdg()) { sb.append(" name=\"").append(ds.getName()).append("(").append(ds.getOffset()).append(")") .append("\""); } else { sb.append(" name=\"").append(ds.getName()).append("\""); } sb.append("/>"); } } sb.append("</dataDescription>"); } return sb.toString(); } /** * * @param value * @return */ private String createLocks(String value) { List<Lock> locks = ValueParser.loadLocks(value); if (locks.isEmpty()) { return ""; } StringBuilder sb = new StringBuilder(); for (Lock lock : locks) { sb.append("<lock"); sb.append(" name=\"").append(lock.getName()).append("\"/>"); } return sb.toString(); } }