View Javadoc
1 /* ==================================================================== 2 * License: 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * 3. The end-user documentation included with the redistribution, 17 * if any, must include the following acknowledgment: 18 * "This product includes software developed by 19 * Robert Half International (http://www.rhi.com/)." 20 * Alternately, this acknowledgment may appear in the software itself, 21 * if and wherever such third-party acknowledgments normally appear. 22 * 23 * 4. The names "Parc", "RHI", and "Robert Half International" must 24 * not be used to endorse or promote products derived from this 25 * software without prior written permission. For written 26 * permission, please contact pete.mckinstry@rhi.com. 27 * 28 * 5. Products derived from this software may not be called "PARC", 29 * nor may "PARC" appear in their name, without prior written 30 * permission of Robert Half International. 31 * 32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 33 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 35 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 36 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 37 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 38 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 39 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 40 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 41 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 42 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * ==================================================================== 45 * 46 */ 47 package com.rhi.architecture.parc; 48 49 import com.rhi.architecture.logging.Logger; 50 import com.rhi.architecture.resource.InitializationException; 51 import com.rhi.architecture.resource.ResourceContext; 52 53 import java.util.ArrayList; 54 import java.util.List; 55 import java.util.ListIterator; 56 import java.util.Properties; 57 58 /*** 59 * The ProcessSet is a group of processes that are run serially. It 60 * is an implementation of the composite element of GOF Composite 61 * pattern. 62 * 63 * @author Pete McKinstry 64 * @copyright 2002, Robert Half Int'l., Inc. All rights reserved. 65 * 66 * @since 1.0 67 */ 68 public final class ProcessSet implements Process { 69 70 private List processes; 71 private Logger log; 72 private String name; 73 74 /*** 75 * Constructor 76 */ 77 public ProcessSet() { 78 this.processes = new ArrayList(); 79 } 80 /*** 81 * The ProcessSet is initialized by loading all Process definitions 82 * immediately under this ProcessSet definition. 83 * 84 * Processes are configured by providing 2 bootstrap configuration 85 * values. The first is the name of the class which implements the 86 * Process interface and provides the functionality which this 87 * Process needs to execute. The 2nd value is the name by which the 88 * Process should be known. This 2nd value is important to 89 * differentiate configuration data between 2 processes w/in the 90 * same PBApplication which both use the same Process class. 91 * For example, here is what the HR interface would look like: 92 * RootProcess.type = "com.rhi.architecture.parc.ProcessSet" 93 * RootProcess.name = "HRProcessSet" 94 * HRProcessSet.Process0.type = "com.rhi.architecture.parc.PipelineProcess" 95 * HRProcessSet.Process0.name = "rhmjp_hrogst" 96 * HRProcessSet.Process1.type = "com.rhi.architecture.parc.PipelineProcess" 97 * HRProcessSet.Process1.name = "rhmjp_hrofile" 98 * Both the type & the name must be provided for the configuration to 99 * be considered valid. Processes are loaded based on incremental 100 * values, meaning the number (see above) is incremented until no 101 * Process settings are found. If the number of Processes loaded is 102 * = 0, it is considered an error, and an InitializationException 103 * is thrown. 104 * 105 * @param props 106 * @throws InitializationException 107 * 108 * @since 1.0 109 */ 110 public void init(Properties props) throws InitializationException { 111 112 ResourceContext ctx = new ResourceContext(); 113 114 // concrete logger impl 115 this.log = (Logger) ctx.lookup(Logger.KEY); 116 if (log == null) { 117 throw new InitializationException("Logger implementation not found."); 118 } 119 120 try { 121 // Processes to be added to the pipeline in numeric order, 122 // until a number is missing. The numbering starts w/ 0. 123 int count = 0; 124 while (true) { 125 StringBuffer buf = new StringBuffer(); 126 buf.append(getName()); 127 buf.append(Process.SEPARATOR); 128 buf.append("Process"); 129 buf.append(count); 130 buf.append(Process.SEPARATOR); 131 String baseName = buf.toString(); // ex: RootProcess.Process0. 132 log.info("attempting to load " + baseName); 133 String processClassName = 134 props.getProperty(baseName + Process.TYPE); 135 if (processClassName == null) { 136 break; 137 } 138 String processName = 139 props.getProperty(baseName + Process.NAME); 140 if (processName == null) { 141 throw new InitializationException( 142 baseName + Process.NAME + " missing from configuration"); 143 } 144 Class processClass = Class.forName(processClassName); 145 Process process = (Process) processClass.newInstance(); 146 process.setName(processName); 147 Properties subProperties = new Properties(props); 148 process.init(subProperties); 149 add(process); 150 count++; 151 } 152 if (count == 0) { 153 log.error("No processes found for ProcessSet."); 154 throw new InitializationException("No processes found for ProcessSet."); 155 } 156 } 157 catch (ClassNotFoundException e) { 158 log.error("ClassNotFoundException.", e); 159 throw new InitializationException("ClassNotFoundException.", e); 160 } 161 catch (InstantiationException e) { 162 log.error("InstantiationException.", e); 163 throw new InitializationException("InstantiationException.", e); 164 } 165 catch (IllegalAccessException e) { 166 log.error("IllegalAccessException.", e); 167 throw new InitializationException("IllegalAccessException.", e); 168 } 169 } 170 171 /*** 172 * Run each Process w/in the set serially in the order they 173 * were added. . 174 * 175 * @exception ProcessingException 176 * 177 * @since 1.0 178 */ 179 public void run() throws ProcessingException { 180 ListIterator iter = processes.listIterator(); 181 while (iter.hasNext()) { 182 Process p = null; 183 try { 184 p = (Process) iter.next(); 185 p.run(); 186 } 187 catch (ProcessingException e) { 188 log.error("ProcessingException thrown by " + p.getName(), e); 189 throw e; 190 } 191 } 192 } 193 194 /*** 195 * Add a new process to the set. New processes are appended to the 196 * end of the list & run in that order. 197 * 198 * @param p 199 * 200 * @since 1.0 201 */ 202 public void add(Process p) { 203 processes.add(p); 204 } 205 206 /*** 207 * Perform any cleanup required. This allows the Process to 208 * keep resources open after the run() method in case a 209 * multi-call strategy is used to execute run() repeatedly. 210 * 211 * @since 1.0 212 */ 213 public void cleanup() { 214 ListIterator iter = processes.listIterator(); 215 Process p = null; 216 while (iter.hasNext()) { 217 p = (Process) iter.next(); 218 p.cleanup(); 219 } 220 } 221 222 /*** 223 * getName returns the configured name for this process. This 224 * method must return a unique identifier for each process 225 * running w/in the same BatchApplication. It is used to 226 * identify properties that are specific to a given Process. 227 * 228 * @return String 229 * 230 * @since 1.0 231 */ 232 public String getName() { 233 // if the name has not been set, use the class name (w/ package stripped) 234 if (name == null) { 235 String tmp = ProcessSet.class.getName(); 236 int idx = tmp.lastIndexOf("."); 237 return tmp.substring(idx + 1); 238 } 239 return name; 240 } 241 242 /*** 243 * setName is called by the framework to provide the correct 244 * process name. 245 * 246 * @param name 247 * 248 * @since 1.0 249 */ 250 public void setName(String name) { 251 this.name = name; 252 } 253 254 }

This page was automatically generated by Maven