View Javadoc

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   * 	&lt;job&gt;
59   * 		&lt;!-- The class that implements the Job interface --&gt;
60   * 		&lt;class&gt;the.implementing.class.of.the.Job&lt;/class&gt;
61   * 		&lt;!-- The display name of the job --&gt;
62   * 		&lt;name&gt;Job Display Name&lt;/name&gt;
63   * 		&lt;fields&gt;
64   * 			&lt;field&gt;
65   * 				&lt;name&gt;field&lt;/name&gt;
66   * 				&lt;value&gt;Some Value&lt;/value&gt;
67   * 			&lt;/field&gt;
68   * 			&lt;field&gt;
69   * 				&lt;name&gt;someOtherField&lt;/name&gt;
70   * 				&lt;value&gt;Some Other Value&lt;/value&gt;
71   * 			&lt;/field&gt;
72   * 		&lt;/fields&gt;
73   * 	&lt;/job&gt;
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 }