1 /*
2 * $HeadURL: $
3 * $Date: $
4 * $Revision: $
5 * $Author: $
6 *
7 * Copyright (c) 2006 MindTree Consulting Ltd.
8 *
9 * This file is part of Insight.
10 *
11 * Insight is free software: you can redistribute it and/or modify it under the
12 * terms of the GNU General Public License as published by the Free Software
13 * Foundation, either version 3 of the License, or (at your option) any later
14 * version.
15 *
16 * Insight is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
19 * Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * Insight. If not, see <http://www.gnu.org/licenses/>.
23 */
24 package com.mindtree.techworks.insight.reporting.jobs;
25
26 import java.util.Iterator;
27 import java.util.Map;
28
29 import org.w3c.dom.Document;
30 import org.w3c.dom.Element;
31 import org.w3c.dom.NodeList;
32
33 import com.mindtree.techworks.insight.reporting.InitializationException;
34 import com.mindtree.techworks.insight.reporting.SerializationXmlUtils;
35
36
37 /**
38 * Handles the serialization and deserialization of <code>Job</code>s.
39 * <p>
40 * The fields that are to be serialized are got from the
41 * {@link Job#getSerializableFields() Job#getSerializableFields()} method.
42 * Unlike <code>Verifier</code>s the <code>Job</code>'s serialization is
43 * kept simple. No <code>Array</code> or <code>Collection</code> fields are
44 * allowed for serialization. Infact, the serialization algorithm does not even
45 * bother to check the type of the field being serialized, and simply calls the
46 * <code>toString()</code> method on it.
47 * </p>
48 * <p>
49 * For deserialization the
50 * {@link Job#setDeserializedField(String, String) Job#setDeserializedField (String, String)}
51 * method is used to set the field value with the name, the particular
52 * <code>Job</code> is supposed to set the field accordingly.
53 * </p>
54 * <h3>Serialized Job</h3>
55 * <p>
56 * The format to serialize a <code>Job</code> is as below:
57 * <pre>
58 * <job>
59 * <!-- The class that implements the Job interface -->
60 * <class>the.implementing.class.of.the.Job</class>
61 * <!-- The display name of the job -->
62 * <name>Job Display Name</name>
63 * <fields>
64 * <field>
65 * <name>field</name>
66 * <value>Some Value</value>
67 * </field>
68 * <field>
69 * <name>someOtherField</name>
70 * <value>Some Other Value</value>
71 * </field>
72 * </fields>
73 * </job>
74 * </pre>
75 *
76 * Unlike <code>Verifier</code>s, the format cannot be varied by the <code>Job</code> implementations.
77 * </p>
78 *
79 * @see com.mindtree.techworks.insight.reporting.jobs.Job
80 *
81 * @author <a href="mailto:bindul_bhowmik@mindtree.com">Bindul Bhowmik</a>
82 * @version $Revision: 27 $ $Date: 2007-12-16 04:58:03 -0700 (Sun, 16 Dec 2007) $
83 * @since Insight 1.5
84 */
85 public class JobPersistanceHandler {
86
87 // -------------------------------------------------------------------------
88 // Constants
89 // -------------------------------------------------------------------------
90
91 /**
92 * The root tag of the XML serialized Job
93 */
94 public static final String SERIALIZED_JOB_ROOT_TAG = "job";
95
96 // -------------------------------------------------------------------------
97 // Public methods
98 // -------------------------------------------------------------------------
99
100 /**
101 * Creates a serialized form of the <code>Job</code>. For the format of
102 * the serialized <code>Job</code> see documentation for this class.
103 *
104 * @param job
105 * The job to be serialized.
106 * @return String containing the XML form of the serialized job.
107 */
108 public static String serializeJob (Job job) {
109
110 StringBuffer serializedJob = new StringBuffer ();
111 serializedJob.append ("<");
112 serializedJob.append (SERIALIZED_JOB_ROOT_TAG);
113 serializedJob.append (">");
114
115 // The implementation class
116 serializedJob.append ("<class>");
117 serializedJob.append (job.getClass ().getName ());
118 serializedJob.append ("</class>");
119
120 // The type of the verifier
121 serializedJob.append ("<name>");
122 serializedJob.append (job.getDisplayName ());
123 serializedJob.append ("</name>");
124
125 // Verifier fields
126 serializedJob.append ("<fields>");
127 Map fields = job.getSerializableFields ();
128 for (Iterator fieldItr = fields.keySet ().iterator (); fieldItr
129 .hasNext ();) {
130 String fieldName = (String) fieldItr.next ();
131 Object fieldValue = fields.get (fieldName);
132
133 // Write the field:
134 serializedJob.append ("<field>");
135
136 // Name of the field
137 serializedJob.append ("<name>");
138 serializedJob.append (fieldName);
139 serializedJob.append ("</name>");
140
141 serializedJob.append ("<value>");
142 serializedJob.append (SerializationXmlUtils
143 .escapeSpecialChars (fieldValue.toString ()));
144 serializedJob.append ("<value>");
145
146 serializedJob.append ("</field>");
147 }
148 serializedJob.append ("</fields>");
149
150
151 serializedJob.append ("</");
152 serializedJob.append (SERIALIZED_JOB_ROOT_TAG);
153 serializedJob.append (">");
154
155 return serializedJob.toString ();
156 }
157
158 /**
159 * Deserializes a job from the persistant format.
160 *
161 * @param serializedJob
162 * The string representing the serialized <code>Job</code>
163 * @return The serialized <code>Job</code>
164 * @throws JobInitializationException
165 * If the <code>Job</code> cannot be deserialized.
166 */
167 public static Job deserializeJob (String serializedJob)
168 throws JobInitializationException {
169
170 Job deserializedJob = null;
171
172 // Get the verifier class
173 Document document = null;
174 try {
175 document = SerializationXmlUtils.createDocument (serializedJob);
176 } catch (InitializationException e) {
177 throw new JobInitializationException (
178 "Could not create XML document", e);
179 }
180
181 String className = null;
182 try {
183 className = SerializationXmlUtils
184 .getSerializedObjectClassName (document);
185 } catch (InitializationException e) {
186 throw new JobInitializationException (
187 "Could not get class for Job.", e);
188 }
189
190 try {
191 // Get the instance.
192 deserializedJob = (Job) Class.forName (className).newInstance ();
193
194 } catch (InstantiationException e) {
195 throw new JobInitializationException (
196 "Could not get Job class or instance.");
197 } catch (IllegalAccessException e) {
198 throw new JobInitializationException (
199 "Could not get Job class or instance.");
200 } catch (ClassNotFoundException e) {
201 throw new JobInitializationException (
202 "Could not get Job class or instance.");
203 }
204
205 // Get the fields element
206 Element documentElement = document.getDocumentElement (); // <job/>
207 NodeList fieldsList = documentElement.getElementsByTagName ("fields");
208
209 // We will take just the first one!
210 if (fieldsList.getLength () > 0) {
211 Element fieldsRoot = (Element) fieldsList.item (0);
212 NodeList fields = fieldsRoot.getElementsByTagName ("field");
213 for (int i = 0; i < fields.getLength (); i++ ) {
214 processField ((Element) fields.item (i), deserializedJob);
215 }
216 }
217
218 return deserializedJob;
219 }
220
221 // -------------------------------------------------------------------------
222 // Private utility methods
223 // -------------------------------------------------------------------------
224
225 /**
226 * Process the section of the serialized <code>Job</code> corresponding to
227 * a single field in the <code>Job</code>. It uses the
228 * {@link Job#setDeserializedField(String, String) Job#setDeserializedField(String, String)}
229 * method to populate the fields. If a field is an array, then the method is
230 * called multiple times with the same <code>fieldName</code> but the
231 * different values of the <code>fieldValue</code>.
232 *
233 * @param field
234 * The <code>Element</code> representing the field to
235 * deserialize.
236 * @param job
237 * The <code>Job</code> which is being deserialized.
238 * @throws JobInitializationException
239 * If there is an error deserializing the field.
240 */
241 private static void processField (Element field, Job job)
242 throws JobInitializationException {
243
244 // Get the name of the field - should be only one, taking the first one.
245 Element nameElement = (Element) field.getElementsByTagName ("name")
246 .item (0);
247
248 if (null == nameElement) {
249 throw new JobInitializationException ("Each field needs a name!");
250 }
251
252 String name = SerializationXmlUtils.getTextValue (nameElement);
253
254 // Get the values... should be only one, if not let the Job handle it!
255 NodeList values = field.getElementsByTagName ("value");
256 for (int i = 0; i < values.getLength (); i++ ) {
257 String value = SerializationXmlUtils.getTextValue ((Element) values
258 .item (i));
259
260 // Set the value
261 job.setDeserializedField (name, value);
262 }
263 }
264
265 }