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 }