Package nexj.core.meta.integration

Source Code of nexj.core.meta.integration.TransformationMapping

// Copyright 2010 NexJ Systems Inc. This software is licensed under the terms of the Eclipse Public License 1.0
package nexj.core.meta.integration;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import nexj.core.meta.MetadataException;
import nexj.core.meta.MetadataMarker;
import nexj.core.meta.MetadataValidationException;
import nexj.core.meta.NamedMetadataObject;
import nexj.core.meta.Primitive;
import nexj.core.scripting.Machine;
import nexj.core.scripting.Pair;
import nexj.core.scripting.Symbol;
import nexj.core.util.Undefined;

/**
* Transformation mapping for translating between multiple source values
* and one destination value.
*/
public class TransformationMapping extends NamedMetadataObject
{
   // constants

   /**
    * The Transformer.transformNested() method symbol.
    */
   protected final static Symbol TRANSFORM_NESTED = Symbol.define("transformNested");

   // attributes

   /**
    * The mapping script ordinal number in the transformation.
    */
   protected int m_nOrdinal;
  
   /**
    * The last collection destination ordinal number.
    */
   protected int m_nLastCollectionDestinationOrdinal = -1;

   /**
    * Generation bit mask.
    */
   protected byte m_nGeneration;

   // associations

   /**
    * The condition expression.
    */
   protected Object m_condition = Boolean.TRUE;

   /**
    * The mapping script.
    */
   protected Pair m_script;

   /**
    * The destination root end-point part.
    */
   protected EndpointPart m_rootPart;

   /**
    * The destination end-point part collection.
    */
   protected List m_destinationList = new ArrayList(2); // of type EndpointPart

   /**
    * The transformation mapping argument collection.
    */
   protected List m_argumentList = new ArrayList(2); // of type TransformationArgument
  
   /**
    * An array of fixed association flags corresponding to TransformationSource level
    */
   protected boolean m_bFixedSrcArray[];
  
   /**
    * An array of fixed association flags corresponding to destination end-point part level
    */
   protected boolean m_bFixedDstArray[];

   /**
    * The closest collection parent transformation source.
    */
   protected TransformationSource m_collectionParent;

   /**
    * The transformation expression. Evaluates to the name of the nested transformation
    * to use.
    */
   protected Object m_transformation;

   /**
    * The transformation arguments expression.
    */
   protected Pair m_transformationArguments;

   /**
    * The expression evaluating to the input to the transformation; null to
    * use the first source instead.
    */
   protected Object m_transformationInput;

   // constructors
  
   /**
    * Constructs the metadata object.
    * @param sName The transformation mapping name.
    */
   public TransformationMapping(String sName)
   {
      super(sName);
   }

   // operations

   /**
    * Sets the destination root end-point part.
    * @param rootPart The destination root end-point part to set.
    */
   public void setRootPart(EndpointPart rootPart)
   {
      verifyNotReadOnly();
      m_rootPart = rootPart;
   }

   /**
    * @return The destination root end-point part.
    */
   public EndpointPart getRootPart()
   {
      return m_rootPart;
   }

   /**
    * Adds a new destination end-point part to the mapping.
    * @param sName The name of the end-point part.
    * @param bFixed Indicates fixed collection.
    */
   public void addDestination(String sName, boolean bFixed)
   {
      EndpointPart part = (m_destinationList.isEmpty()) ? m_rootPart :
         (EndpointPart)m_destinationList.get(m_destinationList.size() - 1);
     
      if (part.isPrimitive())
      {
         throw new MetadataException("err.meta.transformation.primitiveParent", new Object[]{part.getName()});
      }

      addDestination(part.getChild(sName), bFixed);
   }
  
   /**
    * Adds a new destination end-point part to the mapping.
    * @param destination The destination end-point part to add.
    * @param bFixed Indicates fixed collection.
    */
   public void addDestination(EndpointPart destination, boolean bFixed)
   {
      verifyNotReadOnly();

      if (destination.isCollection() && !bFixed)
      {
         m_nLastCollectionDestinationOrdinal = m_destinationList.size();
      }

      m_destinationList.add(destination);
      setFixedDestination(m_destinationList.size() - 1, bFixed);
   }

   /**
    * Gets a destination end-point part by ordinal number.
    * @param nOrdinal The destination end-point part ordinal number (0-based).
    * @return The destination end-point part.
    */
   public EndpointPart getDestination(int nOrdinal)
   {
      return (EndpointPart)m_destinationList.get(nOrdinal);
   }

   /**
    * @return The destination end-point part count.
    */
   public int getDestinationCount()
   {
      return m_destinationList.size();
   }

   /**
    * @return The last collection destination ordinal number.
    */
   public int getLastCollectionDestinationOrdinal()
   {
      return m_nLastCollectionDestinationOrdinal;
   }
  
   /**
    * Adds a new transformation argument to the mapping.
    * @param nOrdinal The ordinal number of the argument.
    * @param argument The transformation argument to add.
    */
   public void addArgument(int nOrdinal, TransformationArgument argument)
   {
      verifyNotReadOnly();

      if (argument.getName() != null)
      {
         for (int i = m_argumentList.size() - 1; i >= 0; --i)
         {
            if (argument.getName().equals(((TransformationArgument)m_argumentList.get(i)).getName()))
            {
               throw new MetadataException("err.meta.transformation.argumentDup",
                  new Object[]{argument.getName(), getName()});
            }
         }
      }

      m_argumentList.add(nOrdinal, argument);
   }

   /**
    * Adds a new transformation argument to the mapping.
    * @param argument The transformation argument to add.
    */
   public void addArgument(TransformationArgument argument)
   {
      addArgument(m_argumentList.size(), argument);
   }

   /**
    * Gets a transformation mapping argument by ordinal number.
    * @param nOrdinal The transformation mapping argument ordinal number (0-based).
    * @return The transformation mapping argument object.
    */
   public TransformationArgument getArgument(int nOrdinal)
   {
      return (TransformationArgument) m_argumentList.get(nOrdinal);
   }

   /**
    * Removes a transformation mapping argument by ordinal number.
    * @param nOrdinal The transformation mapping argument ordinal number.
    */
   public void removeArgument(int nOrdinal)
   {
      m_argumentList.remove(nOrdinal);
   }
  
   /**
    * @return The transformation mapping argument count.
    */
   public int getArgumentCount()
   {
      return m_argumentList.size();
   }

   /**
    * @return An iterator for the contained transformation argument objects.
    */
   public Iterator getArgumentIterator()
   {
      return m_argumentList.iterator();
   }
  
   /**
    * Sets the condition expression.
    * @param condition The condition expression to set.
    */
   public void setCondition(Object condition)
   {
      verifyNotReadOnly();
      m_condition = condition;
   }

   /**
    * @return The condition expression.
    */
   public Object getCondition()
   {
      return m_condition;
   }
  
   /**
    * Sets the mapping script.
    * @param script The mapping script to set.
    */
   public void setScript(Pair script)
   {
      verifyNotReadOnly();
      m_script = script;
   }

   /**
    * @return The mapping script.
    */
   public Pair getScript()
   {
      return m_script;
   }

   /**
    * Sets the nested transformation to be executed by this mapping.
    * @param transformation An expression that evaluates to the name of
    * the transformation to execute; null if not set.
    */
   public void setTransformation(Object transformation)
   {
      verifyNotReadOnly();
      m_transformation = transformation;
   }

   /**
    * Gets the nested transformation to be executed by this mapping.
    * @return Expression evaluating to the name of the transformation.
    */
   public Object getTransformation()
   {
      return m_transformation;
   }

   /**
    * Sets the nested transformation parameters.
    * @param arguments A list of expressions evaluating to the parameters
    * for the nested transformation; may be null.
    */
   public void setTransformationArguments(Object arguments)
   {
      verifyNotReadOnly();
      m_transformationArguments = new Pair(Symbol.LIST, arguments);
   }

   /**
    * Gets the nested transformation parameters.
    * @return A list of expressions evaluating to the parameters for the
    * nested transformation.
    */
   public Object getTransformationArguments()
   {
      return (m_transformationArguments == null) ? null : m_transformationArguments.getTail();
   }

   /**
    * Sets the nested transformation input.
    * @param input An expression evaluating to the TransferObject to use
    * as input to the nested transformation; null to use the first source.
    */
   public void setTransformationInput(Object input)
   {
      verifyNotReadOnly();
      m_transformationInput = input;
   }

   /**
    * Gets the nested transformation input.
    * @return An expression evaluating to the TransferObject to use as input
    * to the nested transformation; null to use the first source.
    */
   public Object getTransformationInput()
   {
      return m_transformationInput;
   }

   /**
    * Sets the mapping script ordinal number in the transformation.
    * @param nOrdinal The mapping script ordinal number in the transformation (0-based) to set.
    */
   public void setOrdinal(int nOrdinal)
   {
      verifyNotReadOnly();
      m_nOrdinal = nOrdinal;
   }

   /**
    * @return The mapping script ordinal number in the transformation.
    */
   public int getOrdinal()
   {
      return m_nOrdinal;
   }

   /**
    * Adds the mapping to an associated source (through the arguments).
    * @param The containing transformation
    */
   protected void addToSource(Transformation transformation)
   {
      int nCount = getArgumentCount();
     
      if (nCount == 0)
      {
         MetadataValidationException e = new MetadataValidationException(
            "err.meta.transformation.sourceRequired", new Object[]{getName()});

         transformation.setProperties(e);
         setProperties(e);

         throw e;
      }
   
      if (getDestinationCount() == 0)
      {
         return;
      }
     
      int nLevel = 0;
      int nOrdinal = 0;
      int nColLevel = -1;
     
      for (int i = 0; i != nCount; ++i)
      {
         TransformationSource src = getArgument(i).getSource();
         int nCollectionLevel = -1;
        
         for (int k = src.getLevel(); k >= 0; --k)
         {
            if (src.getPath(k).getPart().isCollection())
            {
               nCollectionLevel = k;
              
               break;
            }
         }

         if (nCollectionLevel > nColLevel ||
            src.getLevel() > nLevel && nCollectionLevel >= nColLevel)
         {
            nLevel = src.getLevel();
            nOrdinal = i;
            nColLevel = nCollectionLevel;
         }
      }

      TransformationArgument primaryArg = getArgument(nOrdinal);
      TransformationSource primarySource = primaryArg.getSource();

      primaryArg.setStartLevel(primarySource.getLevel());
      primarySource.addMapping(this);

      for (TransformationSource source = primarySource; source != null; source = source.getParent())
      {
         if (source.getPart().isCollection() && !isFixedSource(source))
         {
            m_collectionParent = source;
            break;
         }
      }
     
      for (int i = 0; i != nCount; ++i)
      {
         if (i == nOrdinal)
         {
            continue;
         }

         TransformationArgument arg = getArgument(i);
         TransformationSource src = arg.getSource();

         for (int k = src.getLevel(); k >= 0; --k)
         {
            TransformationSource path = src.getPath(k);

            if (k <= primarySource.getLevel() && path == primarySource.getPath(k))
            {
               arg.setStartLevel(k);
              
               break;
            }

            if (path.getPart().isCollection())
            {
               MetadataValidationException e = new MetadataValidationException(
                  "err.meta.transformation.parentCollection",
                  new Object[]{src.getPart().getName(), getName()});

               transformation.setProperties(e);
               setProperties(e);

               throw e;
            }
         }
      }
   }

   /**
    * Generates the source code for the mapping.
    * @param transformation The transformation containing the mapping.
    */
   public void generate(Transformation transformation)
   {
      verifyNotReadOnly();

      if (m_nGeneration != 0)
      {
         if (m_nGeneration == 1)
         {
            MetadataValidationException e = new MetadataValidationException(
               "err.meta.transformation.mappingCircularRef", new Object[]{getName()});

            transformation.setProperties(e);
            setProperties(e);

            throw e;
         }

         return;
      }

      ++m_nGeneration;

      boolean bMapping = false;

      for (int nArg = getArgumentCount() - 1; nArg >= 0; --nArg)
      {
         TransformationArgument arg = getArgument(nArg);

         if (arg.getName() == null)
         {
            arg.setName("#arg" + nArg);
         }

         if (arg.getMapping() != null)
         {
            bMapping = true;

            break;
         }
      }

      Pair script = m_script;

      if (m_transformation != null && getArgumentCount() > 0)
      {
         // (#transformer'transformNested TOBJ <Transformation> <Arguments>)
         m_script = Pair.list(
            Pair.list(
               Transformation.TRANSFORMER,
               Pair.quote(TRANSFORM_NESTED),
               (m_transformationInput == null) ? Symbol.define(getArgument(0).getName()) : m_transformationInput,
               m_transformation,
               m_transformationArguments
            )
         );
      }

      if (m_condition != Boolean.TRUE || m_script != null)
      {
         Pair args = null;

         for (int i = getArgumentCount() - 1; i >= 0; --i)
         {
            args = new Pair(Symbol.define(getArgument(i).getName()), args);
         }

         if (bMapping)
         {
            if (m_condition == Boolean.TRUE)
            {
               m_condition = null;
            }
            else
            {
               m_condition = new Pair(m_condition);
            }

            for (int i = getArgumentCount() - 1; i >= 0; --i)
            {
               TransformationArgument arg = getArgument(i);

               if (arg.getMapping() != null)
               {
                  m_condition = new Pair(Pair.binary(Symbol.EQ_P, Symbol.define(arg.getName()),
                     Pair.quote(Undefined.VALUE)).not(), m_condition);
               }
            }

            if (((Pair)m_condition).getTail() == null)
            {
               m_condition = ((Pair)m_condition).getHead();
            }
            else
            {
               m_condition = new Pair(Symbol.AND, m_condition);
            }
         }

         if (m_script != null)
         {
            if (m_condition != Boolean.TRUE)
            {
               m_script = Pair.list(Pair.list(Symbol.IF, m_condition,
                  new Pair(new Pair(Symbol.LAMBDA, new Pair(null, m_script))),
                  Pair.quote(Undefined.VALUE)));
            }
         }
         else
         {
            m_script = Pair.list(Pair.list(Symbol.IF, m_condition,
               args.getHead(), Pair.quote(Undefined.VALUE)));
         }

         m_script = new Pair(Symbol.LAMBDA, new Pair(args, m_script));
      }

      if (bMapping)
      {
         int nNewArgCount = 0;
         Pair args = null;

         for (int nArg = getArgumentCount() - 1; nArg >= 0; --nArg)
         {
            TransformationArgument arg = getArgument(nArg);
            TransformationMapping mapping = arg.getMapping();

            if (mapping != null)
            {
               removeArgument(nArg);
               mapping.generate(transformation);

               Object code = null;
               TransformationArgument srcArg = null;

               for (int i = mapping.getArgumentCount() - 1; i >= 0 ; --i)
               {
                  TransformationArgument mapArg = mapping.getArgument(i);
                  TransformationSource src = mapArg.getSource();
                  int nSrc;

                  for (nSrc = getArgumentCount() - 1; nSrc >= 0; --nSrc)
                  {
                     srcArg = getArgument(nSrc);

                     if (srcArg.getSource() == src)
                     {
                        break;
                     }
                  }

                  if (nSrc < 0)
                  {
                     srcArg = new TransformationArgument("#" + nNewArgCount++);
                     srcArg.setSource(src);
                     srcArg.setNull(mapArg.isNull());
                     srcArg.setDefaultValue(mapArg.getDefaultValue());
                     srcArg.setDefaultValueFunction(mapArg.getDefaultValueFunction());
                     addArgument(nArg, srcArg);
                  }

                  if (arg.isNull())
                  {
                     src.setNull(true);
                  }

                  if (arg.isDefault())
                  {
                     src.setDefault(true);
                  }

                  code = new Pair(Symbol.define(srcArg.getName()), code);
               }

               if (mapping.getOrdinal() == 0)
               {
                  code = ((Pair)code).getHead();
               }
               else
               {
                  code = new Pair(Pair.list(Symbol.VECTOR_REF, Transformation.MAPPERS,
                     Primitive.createInteger(mapping.getOrdinal())), code);
               }

               args = new Pair(code, args);
            }
            else
            {
               args = new Pair(Symbol.define(arg.getName()), args);
            }
         }

         Pair code = null;

         for (int i = getArgumentCount() - 1; i >= 0; --i)
         {
            code = new Pair(Symbol.define(getArgument(i).getName()), code);
         }

         if (m_script == null)
         {
            m_script = Pair.list(Symbol.LAMBDA, code, args.getHead());
         }
         else
         {
            m_script = Pair.list(Symbol.LAMBDA, code, new Pair(m_script, args));
         }
      }

      if (m_script != null)
      {
         if (script != null && script.getHead() == Transformation.BASE)
         {
            // Script was a reference to a base mapping; base ordinal now valid so use it to complete the script.
            TransformationMapping baseMapping = (TransformationMapping)script.getTail();

            m_script = Pair.list(Transformation.BASE, Primitive.createInteger(baseMapping.getOrdinal()));
         }

         m_nOrdinal = transformation.addScript(m_script);
         m_condition = null;
         m_script = null;
      }

      addToSource(transformation);
      ++m_nGeneration;
   }

   /**
    * Compiles the mapping.
    * @param transformation The transformation containing the mapping.
    * @param machine The VM used for compilation.
    */
   public void compile(Transformation transformation, Machine machine)
   {
      for (int i =  0, n = getArgumentCount(); i < n; ++i)
      {
         TransformationArgument arg = getArgument(i);

         if (arg.isDefault())
         {
            arg.setDefaultValueFunction(transformation.compile(
               Pair.list(Symbol.LAMBDA, Pair.list(Symbol.THIS), arg.getDefaultValue()),
               "mapping." + m_sName + '.' + arg.getName(), machine));
         }
      }
   }

   /**
    * Sets a fixed flag in the destination fixed flag array.
    * @param nDestIndex The index for which to set the fixed flag.
    * @param bFixed The desired flag.
    */
   public void setFixedDestination(int nDestIndex, boolean bFixed)
   {
      verifyNotReadOnly();
     
      if (m_bFixedDstArray == null)
      {
         if (!bFixed)
         {
            return;
         }

         m_bFixedDstArray = new boolean[nDestIndex + 4];
      }
      else if (nDestIndex >= m_bFixedDstArray.length)
      {
         boolean bNewArray[] = new boolean[nDestIndex + 4];

         System.arraycopy(m_bFixedDstArray, 0, bNewArray, 0, m_bFixedDstArray.length);
         m_bFixedDstArray = bNewArray;
      }

      m_bFixedDstArray[nDestIndex] = bFixed;     
   }

   /**
    * Sets a fixed flag in the source fixed flag array.
    * @param source The transformation source for which to set the fixed flag.
    * @param bFixed The desired flag.
    */
   public void setFixedSource(TransformationSource source, boolean bFixed)
   {
      verifyNotReadOnly();

      if (m_bFixedSrcArray == null)
      {
         m_bFixedSrcArray = new boolean[source.getLevel() + 4];
      }
      else if (source.getLevel() >= m_bFixedSrcArray.length)
      {
         boolean bNewArray[] = new boolean[source.getLevel() + 4];

         System.arraycopy(m_bFixedSrcArray, 0, bNewArray, 0, m_bFixedSrcArray.length);
         m_bFixedSrcArray = bNewArray;
      }

      m_bFixedSrcArray[source.getLevel()] = bFixed;     
   }

   /**
    * @param source The source for which to return a fixed flag.
    * @return The fixed collection flag for a given source in this mapping.
    */
   public boolean isFixedSource(TransformationSource source)
   {
      if (m_bFixedSrcArray == null)
      {
         return false;
      }
     
      return (source.getLevel() < m_bFixedSrcArray.length) ? m_bFixedSrcArray[source.getLevel()] : false;
   }

   /**
    * @param nDestIndex The array index for which to return a fixed flag.
    * @return The fixed collection flag for a destination index in this mapping.
    */
   public boolean isFixedDestination(int nDestIndex)
   {
      if (m_bFixedDstArray == null)
      {
         return false;
      }
     
      return (nDestIndex < m_bFixedDstArray.length) ? m_bFixedDstArray[nDestIndex] : false;
   }

   /**
    * @return The closest collection parent transformation source.
    */
   public TransformationSource getCollectionParent()
   {
      return m_collectionParent;
   }

   /**
    * @see nexj.core.meta.MetadataObject#setProperties(nexj.core.meta.MetadataMarker)
    */
   public void setProperties(MetadataMarker marker)
   {
      marker.setProperty("mapping", m_sName);
   }

   /**
    * Finishes loading the transformation mapping, first pass.
    * The first pass is where the inherited mappings are fixed up. Two things must be fixed:
    * 1) The path of destination end-point parts on the derived transformation's mapping must
    *    be changed so that it uses parts from the derived transformation's
    *    destination end-point (and not the base transformation's destination end-point).
    * 2) For an inherited mapping, the mapping arguments will not have their source mappings
    *    (if any) set. Get the correct mapping source from the base mapping.
    * @param transformation The transformation containing the mapping.
    * @param machine The VM used for compilation.
    */
   public void finish1(Transformation transformation, Machine machine)
   {
      verifyNotReadOnly();

      // Process only inherited mappings (ensure object references are to objects in the derived transformation)
      if (m_rootPart != transformation.getDestination())
      {
         // Fix the root end-point part and destination end-point part lists.
         EndpointPart part = m_rootPart = transformation.getDestination();

         for (int i = 0; i < m_destinationList.size(); i++)
         {
            EndpointPart oldPart = (EndpointPart)m_destinationList.get(i);

            part = part.getChild(oldPart.getName());
            m_destinationList.set(i, part);
         }

         // Fixup arguments with source mappings
         for (int i = 0, nCount = m_argumentList.size(); i < nCount; i++)
         {
            TransformationArgument arg = (TransformationArgument)m_argumentList.get(i);

            if (arg.getSource() == null)
            {
               assert arg.getMapping() == null;

               TransformationMapping baseMapping = getEquivalentMappingInBase(this, transformation);

               // Find same argument by ordinal position.
               TransformationArgument baseArg = baseMapping.getArgument(i);

               assert baseArg.getSource() == null;
               assert baseArg.getMapping() != null;

               arg.setMapping(transformation.getMapping(baseArg.getMapping().getName()));
            }
         }
      }
   }

   /**
    * Given a mapping and its transformation, finds the equivalent mapping in the
    * base transformation.
    *
    * Works on the principle that the mapping order from base to derived transformation
    * is maintained by inheritance resolution.
    *
    * @param mapping The mapping to find.
    * @param transformation The mapping's transformation.
    * @return The equivalent mapping from the base transformation; null if not found.
    */
   private static TransformationMapping getEquivalentMappingInBase(TransformationMapping mapping, Transformation transformation)
   {
      Iterator baseItr = transformation.getBaseTransformation().getMappingIterator();
      Iterator derivedItr = transformation.getMappingIterator();

      while (baseItr.hasNext())
      {
         TransformationMapping baseMapping = (TransformationMapping)baseItr.next();
         TransformationMapping derivedMapping = (TransformationMapping)derivedItr.next();

         if (derivedMapping == mapping)
         {
            return baseMapping;
         }
      }

      return null;
   }

   /**
    * Finishes loading the transformation mapping, second pass.
    * The second pass is where code generation/compilation is performed.
    * @param transformation The transformation containing the mapping.
    * @param machine The VM used for compilation.
    */
   public void finish2(Transformation transformation, Machine machine)
   {
      // Build the mapping function
      generate(transformation);
      compile(transformation, machine);
   }

   /**
    * @see nexj.core.meta.MetadataObject#clone()
    */
   public Object clone()
   {
      TransformationMapping copy = (TransformationMapping)super.clone();

      copy.m_argumentList = new ArrayList(m_argumentList.size());

      for (int i = 0; i < m_argumentList.size(); i++)
      {
         copy.m_argumentList.add(((TransformationArgument)m_argumentList.get(i)).clone());
      }

      copy.m_destinationList = (ArrayList)((ArrayList)m_destinationList).clone();

      return copy;
   }

   /**
    * @see nexj.core.meta.MetadataObject#makeReadOnly()
    */
   public void makeReadOnly()
   {
      super.makeReadOnly();

      for (Iterator itr = m_argumentList.iterator(); itr.hasNext(); )
      {
         ((TransformationArgument)itr.next()).makeReadOnly();
      }

      ((ArrayList)m_argumentList).trimToSize();
      ((ArrayList)m_destinationList).trimToSize();
   }

   /**
    * @see nexj.core.meta.NamedMetadataObject#toString()
    */
   public String toString()
   {
      StringBuffer buf = new StringBuffer(128);

      buf.append(super.toString());
      buf.append(" to ");

      if (m_rootPart != null)
      {
         buf.append(m_rootPart.getName());
      }

      for (int i = 0, n = getDestinationCount(); i < n; ++i)
      {
         buf.append(' ');
         buf.append(getDestination(i).getName());
      }

      return buf.toString();
   }
}
TOP

Related Classes of nexj.core.meta.integration.TransformationMapping

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.