Package nexj.core.rpc.text

Source Code of nexj.core.rpc.text.TextMarshaller

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

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import java.util.SimpleTimeZone;
import java.util.TimeZone;

import nexj.core.meta.Primitive;
import nexj.core.meta.PrivilegeSet;
import nexj.core.persistence.OID;
import nexj.core.rpc.CharacterStreamMarshaller;
import nexj.core.rpc.ErrorLocationHolder;
import nexj.core.rpc.MarshallerException;
import nexj.core.rpc.Request;
import nexj.core.rpc.Response;
import nexj.core.rpc.TransferObject;
import nexj.core.runtime.Context;
import nexj.core.runtime.ContextAware;
import nexj.core.scripting.ConstPair;
import nexj.core.scripting.Machine;
import nexj.core.scripting.PCodeFunction;
import nexj.core.scripting.PCodeMacro;
import nexj.core.scripting.Pair;
import nexj.core.scripting.Symbol;
import nexj.core.scripting.object.BasicObject;
import nexj.core.scripting.object.ClassObject;
import nexj.core.util.Base64Util;
import nexj.core.util.Binary;
import nexj.core.util.ErrorCode;
import nexj.core.util.ExceptionHolder;
import nexj.core.util.HashTab;
import nexj.core.util.IdentityHashTab;
import nexj.core.util.Lookup;
import nexj.core.util.ObjUtil;
import nexj.core.util.PagedArrayList;
import nexj.core.util.PagedBinary;
import nexj.core.util.PropertyIterator;
import nexj.core.util.StringId;
import nexj.core.util.TZ;

/**
* Text format object marshaller.
*/
public class TextMarshaller implements CharacterStreamMarshaller, ContextAware
{
   // constants

   /**
    * The exception marshaller.
    */
   protected final static Marshaller EXCEPTION_MSH = new Marshaller()
   {
      public void marshal(Object obj, TextMarshaller msh) throws IOException
      {
         Throwable t = (Throwable)obj;

         msh.write(Text.EXCEPTION);

         if (obj instanceof ErrorCode)
         {
            ErrorCode e = (ErrorCode)obj;

            msh.marshal(e.getErrorCode());
            msh.marshal((msh.getContext() != null)
               ? msh.getContext().formatString(e.getErrorCode(), e.getErrorArgs())
               : t.getLocalizedMessage());

            Object[] args = e.getErrorArgs();

            if (args == null)
            {
               msh.write(Text.NULL);
            }
            else
            {
               msh.writePrefix(args.length, Text.SEQUENCE);

               for (int i = 0; i < args.length; ++i)
               {
                  Object arg = args[i];

                  if (arg != null)
                  {
                     if (!msh.m_mshMap.contains(arg.getClass()))
                     {
                        if (msh.m_context != null)
                        {
                           arg = msh.m_context.getStringTable().toString(arg);
                        }
                        else
                        {
                           arg = String.valueOf(arg);
                        }
                     }
                  }

                  msh.marshal(arg);
               }
            }
         }
         else
         {
            msh.marshal("err." + t.getClass().getName());
            msh.marshal(t.getLocalizedMessage());
            msh.write(Text.NULL);
         }

         if (obj instanceof ErrorLocationHolder)
         {
            ErrorLocationHolder h = (ErrorLocationHolder)obj;

            msh.marshal(h.getClassName());
            msh.marshal((h.getOIDHolder() != null) ? h.getOIDHolder().getOID() : null);
            msh.marshal(h.getOrdinal());
            msh.writePrefix(h.getAttributeCount() << 1, Text.SEQUENCE);

            for (Iterator itr = h.getAttributeIterator(); itr.hasNext();)
            {
               String sAttribute = (String)itr.next();

               msh.marshalObj(sAttribute);
               msh.marshal(h.findException(sAttribute));
            }
         }
         else
         {
            msh.write(Text.NULL);
            msh.write(Text.NULL);
            msh.marshal(-1);
            msh.write(Text.NULL);
         }

         if (obj instanceof ExceptionHolder)
         {
            ExceptionHolder h = (ExceptionHolder)obj;
            int nCount = 0;

            for (Iterator itr = h.getExceptionIterator(); itr.hasNext();)
            {
               if (!ObjUtil.isSystem((Throwable)itr.next()))
               {
                  ++nCount;
               }
            }

            msh.writePrefix(nCount, Text.SEQUENCE);

            for (Iterator itr = h.getExceptionIterator(); nCount != 0;)
            {
               Throwable cause = (Throwable)itr.next();

               if (!ObjUtil.isSystem(cause))
               {
                  msh.marshal(cause);
                  --nCount;
               }
            }
         }
         else
         {
            Throwable cause = t.getCause();

            if (cause == null || ObjUtil.isSystem(cause))
            {
               msh.write(Text.NULL);
            }
            else
            {
               msh.writePrefix(1, Text.SEQUENCE);
               msh.marshal(cause);
            }
         }
      }

      public boolean isPrimitive()
      {
         return false;
      }
   };

   /**
    * The marshaller map, class to marshaller implementation.
    */
   protected final static Lookup s_mshMap = new HashTab(64); // of type Marshaller[Class]

   static
   {
      s_mshMap.put(Integer.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            msh.m_buffer.append(((Integer)obj).intValue());
            msh.writePrefix(msh.m_buffer.length(), Text.INTEGER);
            msh.writeBuffer();
         }

         public boolean isPrimitive()
         {
            return true;
         }
      });

      s_mshMap.put(Long.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            msh.m_buffer.append(((Long)obj).longValue());
            msh.writePrefix(msh.m_buffer.length(), Text.LONG);
            msh.writeBuffer();
         }

         public boolean isPrimitive()
         {
            return true;
         }
      });

      s_mshMap.put(Float.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            msh.m_buffer.append(((Float)obj).floatValue());
            msh.writePrefix(msh.m_buffer.length(), Text.FLOAT);
            msh.writeBuffer();
         }

         public boolean isPrimitive()
         {
            return true;
         }
      });

      s_mshMap.put(Double.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            msh.m_buffer.append(((Double)obj).doubleValue());
            msh.writePrefix(msh.m_buffer.length(), Text.DOUBLE);
            msh.writeBuffer();
         }

         public boolean isPrimitive()
         {
            return true;
         }
      });

      s_mshMap.put(BigDecimal.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            String s = obj.toString();
            msh.writePrefix(s.length(), Text.DECIMAL);
            msh.write(s);
         }

         public boolean isPrimitive()
         {
            return true;
         }
      });

      s_mshMap.put(java.util.Date.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            msh.m_buffer.append(((java.util.Date)obj).getTime());
            msh.writePrefix(msh.m_buffer.length(), Text.TIMESTAMP);
            msh.writeBuffer();
         }

         public boolean isPrimitive()
         {
            return true;
         }
      });

      s_mshMap.put(java.sql.Date.class, s_mshMap.get(java.util.Date.class));
      s_mshMap.put(java.sql.Time.class, s_mshMap.get(java.util.Date.class));
      s_mshMap.put(java.sql.Timestamp.class, s_mshMap.get(java.util.Date.class));

      s_mshMap.put(Boolean.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            msh.writePrefix((((Boolean)obj).booleanValue()) ? 1 : 0, Text.BOOLEAN);
         }

         public boolean isPrimitive()
         {
            return true;
         }
      });

      s_mshMap.put(String.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            String s = (String)obj;
            msh.writePrefix(s.length(), Text.STRING);
            msh.write(s);
         }

         public boolean isPrimitive()
         {
            return true;
         }
      });

      s_mshMap.put(StringId.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            String s = ((StringId)obj).toString();

            if (s == null)
            {
               s = "";
            }

            msh.writePrefix(s.length(), Text.STRING_ID);
            msh.write(s);
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(Character.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            msh.writePrefix(1, Text.CHARACTER);
            msh.write(((Character)obj).charValue());
         }

         public boolean isPrimitive()
         {
            return true;
         }
      });

      s_mshMap.put(Binary.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            Binary bin = (Binary)obj;

            msh.writePrefix(((bin.getData().length + 2) / 3) << 2, Text.BINARY);
            msh.write(bin.getData());
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(PagedBinary.class, s_mshMap.get(Binary.class));

      s_mshMap.put(Locale.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            String s = obj.toString();
            msh.writePrefix(s.length(), Text.LOCALE);
            msh.write(s);
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(TimeZone.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            String s = ((TimeZone)obj).getID();
            msh.writePrefix(s.length(), Text.TIME_ZONE);
            msh.write(s);
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(TZ.UTC.getClass(), s_mshMap.get(TimeZone.class));
      s_mshMap.put(SimpleTimeZone.class, s_mshMap.get(TimeZone.class));

      s_mshMap.put(ArrayList.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            ArrayList list = (ArrayList)obj;
            int n = list.size();

            msh.writePrefix(n, Text.ARRAY);

            for (int i = 0; i < n; ++i)
            {
               msh.marshal(list.get(i));
            }
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(PagedArrayList.class, s_mshMap.get(ArrayList.class));

      s_mshMap.put(TransferObject.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            TransferObject tobj = (TransferObject)obj;

            msh.writePrefix(tobj.getValueCount(), Text.TRANSFER_OBJECT);
            msh.marshalObj(tobj.getClassName());
            msh.marshalObj(tobj.getEventName());
            msh.marshal(tobj.getVersion());
            msh.marshal(tobj.getOID());

            for (PropertyIterator itr = tobj.getIterator(); itr.hasNext();)
            {
               msh.marshalObj((String)itr.next());
               msh.marshal(itr.getValue());
            }
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(BasicObject.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            BasicObject bobj = (BasicObject)obj;
            ClassObject classObj = bobj.getClassObject();
            int nCount = classObj.resolveAttributeCount();
            Machine machine = (msh.m_context == null) ? null : msh.m_context.getMachine();

            msh.writePrefix(nCount, Text.BASIC_OBJECT);
            msh.marshal(classObj.getSymbol());

            for (int i = 0; i < nCount; i++)
            {
               msh.marshal(bobj.getValue(i, machine));
            }
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(OID.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            OID oid = (OID)obj;

            msh.write(Text.OID);

            int n = oid.getCount();

            msh.writePrefix(n, Text.SEQUENCE);

            for (int i = 0; i < n; ++i)
            {
               msh.marshal(oid.getValue(i));
            }
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(Symbol.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            String s = ((Symbol)obj).getName();

            msh.writePrefix(s.length(), Text.SYMBOL);
            msh.write(s);
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(Pair.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            Pair pair = (Pair)obj;

            msh.write(Text.PAIR);
            msh.marshal(pair.getHead());
            msh.marshal(pair.getTail());
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(ConstPair.class, s_mshMap.get(Pair.class));

      s_mshMap.put(byte[].class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            byte[] nArray = (byte[])obj;

            msh.writePrefix(((nArray.length + 2) / 3) << 2, Text.BVECTOR);
            msh.write(nArray);
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(char[].class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            char[] cbuf = (char[])obj;
            int n = cbuf.length;

            msh.writePrefix(n, Text.CVECTOR);

            // Replace NUL with \uFFFF to work around the IE XMLHTTP zstring bug
            for (int i = 0; i < n; ++i)
            {
               char ch = cbuf[i];

               msh.write((ch == 0) ? '\uFFFF' : ch);
            }
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(String[].class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            String[] array = (String[])obj;
            int n = array.length;

            msh.writePrefix(n, Text.SVECTOR);

            for (int i = 0; i < n; ++i)
            {
               msh.marshal(array[i]);
            }
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(Object[].class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            Object[] array = (Object[])obj;
            int n = array.length;

            msh.writePrefix(n, Text.VECTOR);

            for (int i = 0; i < n; ++i)
            {
               msh.marshal(array[i]);
            }
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(PrivilegeSet.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            byte[] mask = ((PrivilegeSet)obj).getMask();

            msh.writePrefix(mask.length << 1, Text.PRIVILEGE_SET);
            Binary.write(msh.m_writer, mask, 0, mask.length);
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(PCodeFunction.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            PCodeFunction fun = ((PCodeFunction)obj).getCleanCopy();

            msh.write(Text.FUNCTION);
            msh.marshal(fun.code);
            msh.marshal(fun.constants);
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(PCodeMacro.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            PCodeFunction fun = ((PCodeFunction)obj).getCleanCopy();

            msh.write(Text.MACRO);
            msh.marshal(fun.code);
            msh.marshal(fun.constants);
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(Request.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            Request req = (Request)obj;
            int nVersion = msh.m_nVersion;
            int nCount = req.getInvocationCount();

            msh.writePrefix((nVersion >= 4) ? nCount : 0, Text.REQUEST);
            msh.marshal(req.getNamespace());
            msh.marshal(req.getVersion());
            msh.marshal(req.isAsync());
            msh.marshal(req.isCommit());
            msh.marshal(req.getLocale());

            if (nVersion >= 2)
            {
               msh.marshal(req.getTimeZone());
            }

            msh.marshal(req.getCorrelator());

            boolean bParameters = false;
            boolean bAttributes = false;

            if (nVersion <= 3)
            {
               msh.writePrefix(nCount, Text.SEQUENCE);
            }

            for (int i = 0; i < nCount; ++i)
            {
               Request.Invocation invocation = req.getInvocation(i);

               msh.marshal(invocation.getObject());
              
               if (nVersion <= 3)
               {
                  if (!bParameters)
                  {
                     bParameters = (invocation.getArguments() != null);
                  }

                  if (!bAttributes)
                  {
                     bAttributes = (invocation.getAttributes() != null);
                  }
               }
               else
               {
                  msh.marshalObj(invocation.getEventName());
                  msh.marshal(invocation.getArguments());
                  msh.marshal(invocation.getAttributes());
               }
            }

            if (nVersion <= 3)
            {
               if (nVersion == 3)
               {
                  if (bParameters)
                  {
                     msh.writePrefix(nCount, Text.SEQUENCE);

                     for (int i = 0; i < nCount; ++i)
                     {
                        msh.marshal(req.getInvocation(i).getArguments());
                     }
                  }
                  else
                  {
                     msh.writePrefix(0, Text.NULL);
                  }
               }

               if (bAttributes)
               {
                  msh.writePrefix(nCount, Text.SEQUENCE);

                  for (int i = 0; i < nCount; ++i)
                  {
                     msh.marshal(req.getInvocation(i).getAttributes());
                  }
               }
               else
               {
                  msh.writePrefix(0, Text.NULL);
               }
            }

            nCount = req.getFilterCount();
            msh.writePrefix(nCount, Text.SEQUENCE);

            for (int i = 0; i < nCount; ++i)
            {
               msh.marshal(req.getFilter(i));
            }
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });

      s_mshMap.put(Response.class, new Marshaller()
      {
         public void marshal(Object obj, TextMarshaller msh) throws IOException
         {
            Response resp = (Response)obj;

            msh.write(Text.RESPONSE);

            int n = resp.getResultCount();

            msh.writePrefix(n, Text.SEQUENCE);

            for (int i = 0; i < n; ++i)
            {
               msh.marshal(resp.getResult(i));
            }

            n = resp.getEventCount();
            msh.writePrefix(n, Text.SEQUENCE);

            for (int i = 0; i < n; ++i)
            {
               msh.marshal(resp.getEvent(i));
            }
         }

         public boolean isPrimitive()
         {
            return false;
         }
      });
   }

   // attributes

   /**
    * The serialization format version.
    */
   protected int m_nVersion = 4;

   // associations

   /**
    * The working string buffer.
    */
   protected StringBuilder m_buffer = new StringBuilder(32);

   /**
    * The number conversion buffer.
    */
   protected char[] m_cvtBuf = new char[10];

   /**
    * The object class to marshaller map: Marshaller[Class].
    */
   protected Lookup m_mshMap;

   /**
    * The object reference map.
    */
   protected Lookup m_objectMap;

   /**
    * The character stream writer.
    */
   protected Writer m_writer;

   /**
    * The Base64 input stream.
    */
   protected Base64InputStream m_istream64;

   /**
    * The runtime context.
    */
   protected Context m_context;

   // constructors

   /**
    * Creates a text marshaller with a given runtime context.
    * @param context The runtime context.
    */
   public TextMarshaller(Context context)
   {
      m_context = context;
   }

   // operations

   /**
    * Sets the runtime context.
    * @param context The context to set.
    */
   public void setContext(Context context)
   {
      m_context = context;
   }

   /**
    * @return The runtime context.
    */
   public Context getContext()
   {
      return m_context;
   }

   /**
    * Sets the serialization format version.
    * @param nVersion The serialization format version to set.
    */
   public void setVersion(int nVersion)
   {
      m_nVersion = nVersion;
   }

   /**
    * @return The serialization format version.
    */
   public int getVersion()
   {
      return m_nVersion;
   }

   /**
    * Writes a character to the output stream.
    * @param ch The character to write.
    */
   protected void write(char ch) throws IOException
   {
      m_writer.write(ch);
   }

   /**
    * Writes a string to the output stream.
    * @param s The string to write.
    */
   protected void write(String s) throws IOException
   {
      m_writer.write(s);
   }

   /**
    * Writes a Base64-encoded byte array to the output stream.
    * @param data The array to write.
    */
   protected void write(byte[] data) throws IOException
   {
      if (m_istream64 == null)
      {
         m_istream64 = new Base64InputStream(data);
      }
      else
      {
         m_istream64.setData(data);
      }

      Base64Util.encode(m_istream64, m_writer, -1, false);
      m_istream64.detach();
   }

   /**
    * Writes a count and type prefix to the output stream.
    * @param nCount The count prefix. Must be non-negative.
    * @param chType The type prefix.
    */
   protected void writePrefix(int nCount, char chType) throws IOException
   {
      String s;

      switch (nCount)
      {
         case 0:
            m_writer.write(chType);
            return;

         case 1:
            s = "1";
            break;

         case 2:
            s = "2";
            break;

         case 3:
            s = "3";
            break;

         case 4:
            s = "4";
            break;

         case 5:
            s = "5";
            break;

         case 6:
            s = "6";
            break;

         case 7:
            s = "7";
            break;

         case 8:
            s = "8";
            break;

         case 9:
            s = "9";
            break;

         case 10:
            s = "10";
            break;

         case 11:
            s = "11";
            break;

         case 12:
            s = "12";
            break;

         case 13:
            s = "13";
            break;

         case 14:
            s = "14";
            break;

         case 15:
            s = "15";
            break;

         case 16:
            s = "16";
            break;

         case 17:
            s = "17";
            break;

         case 18:
            s = "18";
            break;

         case 19:
            s = "19";
            break;

         case 20:
            s = "20";
            break;

         case 21:
            s = "21";
            break;

         case 22:
            s = "22";
            break;

         case 23:
            s = "23";
            break;

         case 24:
            s = "24";
            break;

         case 25:
            s = "25";
            break;

         case 26:
            s = "26";
            break;

         case 27:
            s = "27";
            break;

         case 28:
            s = "28";
            break;

         case 29:
            s = "29";
            break;

         case 30:
            s = "30";
            break;

         case 31:
            s = "31";
            break;

         case 32:
            s = "32";
            break;

         default:
            int i = 0;

            do
            {
               m_cvtBuf[i++] = (char)(nCount % 10 + '0');
               nCount /= 10;
            }
            while (nCount != 0);

            while (i != 0)
            {
               m_writer.write(m_cvtBuf[--i]);
            }

            m_writer.write(chType);

            return;
      }

      m_writer.write(s);
      m_writer.write(chType);
   }

   /**
    * Writes the work buffer contents to the output stream.
    */
   protected void writeBuffer() throws IOException
   {
      int n = m_buffer.length();

      for (int i = 0; i < n; ++i)
      {
         m_writer.write(m_buffer.charAt(i));
      }

      m_buffer.setLength(0);
   }

   /**
    * Marshals an integer value.
    * @param n The integer value to marshal.
    */
   protected void marshal(int n) throws IOException
   {
      m_buffer.append(n);
      writePrefix(m_buffer.length(), Text.INTEGER);
      writeBuffer();
   }

   /**
    * Marshals a long value.
    * @param l The long value to marshal.
    */
   protected void marshal(long l) throws IOException
   {
      m_buffer.append(l);
      writePrefix(m_buffer.length(), Text.LONG);
      writeBuffer();
   }

   /**
    * Marshals a boolean value.
    * @param b The boolean value to marshal.
    */
   protected void marshal(boolean b) throws IOException
   {
      writePrefix((b) ? 1 : 0, Text.BOOLEAN);
   }

   /**
    * Marshals a string as an object.
    * @param s The string to marshal.
    */
   protected void marshalObj(String s) throws IOException
   {
      if (s == null)
      {
         write(Text.NULL);
         return;
      }

      Integer index = (Integer)m_objectMap.get(s);

      if (index != null)
      {
         writePrefix(index.intValue(), Text.REFERENCE);
         return;
      }

      m_objectMap.put(s, Primitive.createInteger(m_objectMap.size()));

      writePrefix(s.length(), Text.STRING_OBJECT);
      write(s);
   }

   /**
    * Marshals an object to the output stream.
    * @param obj The object to marshal.
    */
   protected void marshal(Object obj) throws IOException
   {
      if (obj == null)
      {
         write(Text.NULL);
         return;
      }

      Marshaller msh = (Marshaller)m_mshMap.get(obj.getClass());

      if (msh == null)
      {
         if (obj instanceof Throwable)
         {
            msh = EXCEPTION_MSH;
         }
         else
         {
            throw new TextMarshallerException("err.rpc.mshType",
               new Object[]{obj.getClass().getName()});
         }
      }

      if (!msh.isPrimitive())
      {
         Integer index = (Integer)m_objectMap.get(obj);

         if (index != null)
         {
            writePrefix(index.intValue(), Text.REFERENCE);
            return;
         }

         m_objectMap.put(obj, Primitive.createInteger(m_objectMap.size()));
      }

      msh.marshal(obj, this);
   }

   /**
    * Serializes an object to a character stream.
    * @param obj The object to serialize.
    * @param writer The character stream writer.
    */
   public void serialize(Object obj, Writer writer) throws IOException, MarshallerException
   {
      m_writer = writer;
      m_mshMap = getMarshallerMap();
      m_objectMap = new IdentityHashTab();
      m_buffer.setLength(0);

      writePrefix(m_nVersion, Text.VERSION);
      marshal(obj);
   }

   /**
    * @return The marshaller map.
    */
   protected Lookup getMarshallerMap()
   {
      return s_mshMap;
   }

   /**
    * Determines if an object is supported by the marshaller.
    */
   public static boolean isSerializable(Object obj)
   {
      return obj == null || obj instanceof Throwable || s_mshMap.contains(obj.getClass());
   }

   // inner classes

   /**
    * Interface implemented by text marshallers.
    */
   protected interface Marshaller
   {
      /**
       * Marshals an object of a specific type to the output stream.
       * @param obj The object to marshal.
       * @param msh The text marshaller.
       */
      void marshal(Object obj, TextMarshaller msh) throws IOException;

      /**
       * @return True if the object should not be put in the object table
       */
      boolean isPrimitive();
   }

   /**
    * Binary input stream based on a byte array.
    */
   protected static class Base64InputStream extends ByteArrayInputStream
   {
      /**
       * Creates the input stream.
       * @param data The array that will be used as the stream source.
       */
      public Base64InputStream(byte[] data)
      {
         super(data);
      }

      /**
       * Sets the stream source array.
       * @param data The array to set.
       */
      public void setData(byte[] data)
      {
         this.buf = data;
         this.pos = 0;
         this.count = data.length;
      }

      /**
       * Detaches the source array.
       * @return The stream source array.
       */
      public byte[] detach()
      {
         byte[] data = this.buf;

         this.buf = null;

         return data;
      }
   }
}
TOP

Related Classes of nexj.core.rpc.text.TextMarshaller

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.