package org.zstack.core.job; import org.zstack.header.exception.CloudRuntimeException; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; final class JobContextObject implements Serializable { private final String className; private Map<String, Object> args = new HashMap<String, Object>(); JobContextObject(Job job) { className = job.getClass().getName(); save(job); } private void save(Job obj) { Class<?> currClass = obj.getClass(); Field debugField = null; try { do { for (Field f : currClass.getDeclaredFields()) { if (f.isAnnotationPresent(JobContext.class)) { debugField = f; f.setAccessible(true); Object val = f.get(obj); if (val != null) { assert val instanceof Serializable : val.getClass().getName() + " doesn't implement Serializable"; } args.put(f.getName(), val); } } currClass = currClass.getSuperclass(); } while (currClass != Object.class && currClass != null); } catch (Exception e) { String name = debugField == null ? "Unknown" : debugField.getName(); throw new CloudRuntimeException("Unable to get value of " + obj.getClass().getCanonicalName() + "." + name, e); } } Job load() { try { Class<?> currClass = Class.forName(className); Constructor<?> cons = currClass.getDeclaredConstructor(null); cons.setAccessible(true); Object obj = cons.newInstance(); do { for (Field f : currClass.getDeclaredFields()) { if (f.isAnnotationPresent(JobContext.class)) { f.setAccessible(true); if (!args.containsKey(f.getName())) { String err = String.format("%s.%s is marked as JobContext, however, we cannot find it in previous saved context. DB corrupted? %s binary changed?", currClass.getCanonicalName(), f.getName(), currClass.getCanonicalName()); throw new IllegalArgumentException(err); } Object val = args.get(f.getName()); f.set(obj, val); } } currClass = currClass.getSuperclass(); } while (currClass != Object.class && currClass != null); return (Job) obj; } catch (NoSuchMethodException e) { throw new CloudRuntimeException(String.format("Job %s must have a constructor with zero-argument", className), e); } catch (Exception e) { throw new CloudRuntimeException("Unable to load " + className + " from previous saved context", e); } } }