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