| package org.apache.ode.bpel.obj.migrate; |
| |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Modifier; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.apache.ode.bpel.obj.ExtensibleImpl; |
| |
| /** |
| * Migrate from old Omodel classes to new ones. |
| * @author fangzhen |
| * @see ObjectTraverser |
| */ |
| public class OmOld2new extends AbstractObjectVisitor{ |
| private static final Logger __log = LoggerFactory.getLogger(OmOld2new.class); |
| |
| private static Map<String, String> beanPkgMap = new HashMap<String, String>(); |
| static{ |
| beanPkgMap.put("org.apache.ode.bpel.o", "org.apache.ode.bpel.obj"); |
| beanPkgMap.put("org.apache.ode.bpel.elang.xpath10.o", "org.apache.ode.bpel.elang.xpath10.obj"); |
| beanPkgMap.put("org.apache.ode.bpel.elang.xpath20.o", "org.apache.ode.bpel.elang.xpath20.obj"); |
| beanPkgMap.put("org.apache.ode.bpel.elang.xquery10.o", "org.apache.ode.bpel.elang.xquery10.obj"); |
| } |
| |
| public Object visit(Object obj){ |
| __log.debug("migrating object: " + obj.getClass() + "@" + System.identityHashCode(obj)); |
| Object n; |
| /* |
| * we use two category of visitXXX methods here. The first visitXXX(Object) |
| * return corresponding new object instance without fulfilling its contents, |
| * which avoids recursively call. And then assign the new object. then fill contents. |
| * other wise, on cyclic reference case, the object re-visited but hasn't prepared yet. |
| * However, this workaround assumes that the new object is mutable, which is true in our case. |
| */ |
| if (isMap(obj)){ |
| n = visitMap(obj); |
| }else if (isCollection(obj)){ |
| n = visitCollection(obj); |
| }else if (isArray(obj)){ |
| n = visitArray(obj); |
| }else{ |
| n = visitPojo(obj); |
| } |
| rtab.assign(obj, n); |
| |
| if (isMap(obj)){ |
| visitMap(obj, n); |
| }else if (isCollection(obj)){ |
| visitCollection(obj, n); |
| }else if (isArray(obj)){ |
| visitArray(obj, n); |
| }else{ |
| visitPojo(obj, n); |
| } |
| return n; |
| } |
| |
| |
| @Override |
| protected boolean isCollection(Object old) { |
| return (old instanceof Collection); |
| } |
| |
| private boolean isOmodelBean(Object old){ |
| Class<?> cls = old.getClass(); |
| if (beanPkgMap.containsKey(cls.getPackage().getName()) && |
| !cls.getSimpleName().equals("Serializer")){ |
| return true; |
| } |
| return false; |
| } |
| @Override |
| public Object visitArray(Object old) { |
| throw new UnsupportedOperationException("Create new Array is unsupported"); |
| } |
| |
| private void visitArray(Object obj, Object n) { |
| throw new UnsupportedOperationException("We don't need the method here"); |
| } |
| |
| @Override |
| @SuppressWarnings({ "rawtypes"}) |
| public Object visitCollection(Object old) { |
| Collection o = (Collection) old; |
| try { |
| Collection n = o.getClass().newInstance(); |
| return n; |
| } catch (Exception e){ |
| //should not get here |
| e.printStackTrace(); |
| } |
| return null; |
| } |
| |
| @SuppressWarnings({ "rawtypes", "unchecked" }) |
| private void visitCollection(Object old, Object nu) { |
| Collection o = (Collection) old; |
| Collection n = (Collection) nu; |
| for (Object obj : o){ |
| n.add(traverse.traverseObject(obj)); |
| } |
| } |
| |
| @Override |
| @SuppressWarnings({ "rawtypes", "unchecked" }) |
| public Object visitMap(Object old) { |
| Map o = (Map) old; |
| try{ |
| Map n = o.getClass().newInstance(); |
| return n; |
| }catch (Exception e){ |
| //should not get here |
| e.printStackTrace(); |
| } |
| return null; |
| } |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| private void visitMap(Object obj, Object nu) { |
| Set<Entry> entries = ((Map)obj).entrySet(); |
| Map n = (Map)nu; |
| for (Entry e : entries){ |
| n.put(traverse.traverseObject(e.getKey()), traverse.traverseObject(e.getValue())); |
| } |
| } |
| |
| @Override |
| public Object visitPojo(Object old) { |
| if (!isOmodelBean(old)){ |
| return old; |
| }else{ |
| return initiateNew(old); |
| } |
| } |
| |
| private void visitPojo(Object old, Object n) { |
| if (isOmodelBean(old)){ |
| constructNewOm(old, n); |
| } |
| } |
| /** |
| * construct new omodel instances from old ones. Assume <code>old</code> is an old OmodelBean |
| * @param old |
| * @return |
| */ |
| private Object constructNewOm(Object old, Object tn) { |
| assert tn instanceof ExtensibleImpl; |
| ExtensibleImpl n = (ExtensibleImpl) tn; |
| List<Field> fields = getAllFields(old.getClass()); |
| Map<String, Object> fieldMap = n.getFieldContainer(); |
| for (Field f : fields){ |
| if ((f.getModifiers() & Modifier.STATIC) != 0){ |
| continue; //skip static fields |
| } |
| f.setAccessible(true); |
| try{ |
| String fname = f.getName(); |
| Object fvalue = f.get(old); |
| if (fvalue != null){ |
| fieldMap.put(fname, traverse.traverseObject(fvalue)); |
| }else{ |
| fieldMap.put(fname, null); |
| } |
| } catch (Exception e) { |
| RuntimeException rte = new RuntimeException( |
| "Error when try to construct corresponding new Omodel class from old one:" |
| +old.getClass() + "; Failed on field:" + f.getName()); |
| rte.initCause(e); |
| throw rte; |
| } |
| } |
| n.setClassVersion(1); |
| n.setOriginalVersion(0); |
| return n; |
| } |
| |
| private List<Field> getAllFields(Class cls) { |
| return getAllFieldsRec(cls, new ArrayList<Field>()); |
| } |
| |
| private List<Field> getAllFieldsRec(Class cls, ArrayList<Field> fields) { |
| Class par = cls.getSuperclass(); |
| if (par != null){ |
| getAllFieldsRec(par, fields); |
| } |
| fields.addAll(Arrays.asList(cls.getDeclaredFields())); |
| return fields; |
| } |
| |
| private Object initiateNew(Object old) { |
| String clsName = old.getClass().getName(); |
| String qcls = clsName.replace(".o.", ".obj."); |
| try { |
| Constructor cons = Class.forName(qcls).getConstructor(); |
| cons.setAccessible(true); |
| return cons.newInstance(); |
| } catch (Exception e) { |
| RuntimeException rte = new RuntimeException( |
| "Error when try to initiate corresponding new Omodel class of old one:" |
| + old.getClass()); |
| rte.initCause(e); |
| throw rte; |
| } |
| } |
| |
| @Override |
| public Object visitSet(Object obj) { |
| throw new UnsupportedOperationException("We don't really need this operatiion here"); |
| } |
| } |