Package nexj.core.rpc.text

Source Code of nexj.core.rpc.text.TextUnmarshaller$Unmarshaller

// 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.IOException;
import java.io.Reader;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

import nexj.core.meta.Primitive;
import nexj.core.meta.PrivilegeSet;
import nexj.core.persistence.OID;
import nexj.core.rpc.CharacterStreamUnmarshaller;
import nexj.core.rpc.RPCUtil;
import nexj.core.rpc.Request;
import nexj.core.rpc.Response;
import nexj.core.rpc.TransferObject;
import nexj.core.rpc.UnmarshallerException;
import nexj.core.runtime.Context;
import nexj.core.runtime.ContextAware;
import nexj.core.runtime.ValidationException;
import nexj.core.scripting.Machine;
import nexj.core.scripting.PCodeFunction;
import nexj.core.scripting.PCodeMacro;
import nexj.core.scripting.Pair;
import nexj.core.scripting.SchemeParser;
import nexj.core.scripting.Symbol;
import nexj.core.scripting.object.ClassObject;
import nexj.core.scripting.object.ObjectOriented;
import nexj.core.util.Base64Util;
import nexj.core.util.Binary;
import nexj.core.util.DetachableByteArrayOutputStream;
import nexj.core.util.GenericException;
import nexj.core.util.LocaleUtil;
import nexj.core.util.StringId;

/**
* Text format unmarshaller.
*/
public class TextUnmarshaller implements CharacterStreamUnmarshaller, ContextAware
{
   // attributes

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

   // associations

   /**
    * The unmarshaller array, indexed by type character.
    */
   private final static Unmarshaller[] s_unmshArray = new Unmarshaller[128];

   static
   {
      s_unmshArray[Text.NULL] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return null;
         }
      };

      s_unmshArray[Text.REFERENCE] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return unmsh.m_objectList.get(nCount);
         }
      };

      s_unmshArray[Text.INTEGER] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return Primitive.createInteger(Integer.parseInt(unmsh.read(nCount)));
         }
      };

      s_unmshArray[Text.LONG] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return Primitive.createLong(Long.parseLong(unmsh.read(nCount)));
         }
      };

      s_unmshArray[Text.FLOAT] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return Primitive.createFloat(Float.parseFloat(unmsh.read(nCount)));
         }
      };

      s_unmshArray[Text.DOUBLE] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return Primitive.createDouble(Double.parseDouble(unmsh.read(nCount)));
         }
      };

      s_unmshArray[Text.DECIMAL] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return new BigDecimal(unmsh.read(nCount));
         }
      };

      s_unmshArray[Text.TIMESTAMP] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return new Timestamp(Long.parseLong(unmsh.read(nCount)));
         }
      };

      s_unmshArray[Text.BOOLEAN] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return Boolean.valueOf(nCount != 0);
         }
      };

      s_unmshArray[Text.STRING] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return unmsh.read(nCount);
         }
      };

      s_unmshArray[Text.STRING_OBJECT] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            String s = unmsh.read(nCount);

            unmsh.addObj(s);

            return s;
         }
      };

      s_unmshArray[Text.STRING_ID] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller msh) throws IOException
         {
            StringId id = new StringId(msh.read(nCount));

            msh.addObj(id);

            return id;
         }
      };

      s_unmshArray[Text.CHARACTER] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            return Primitive.createCharacter(unmsh.read());
         }
      };

      s_unmshArray[Text.BINARY] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            Binary bin = new Binary(unmsh.readBase64(nCount));

            unmsh.addObj(bin);

            return bin;
         }
      };

      s_unmshArray[Text.LOCALE] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            Locale locale = LocaleUtil.parse(unmsh.read(nCount));

            unmsh.addObj(locale);

            return locale;
         }
      };

      s_unmshArray[Text.TIME_ZONE] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            TimeZone timeZone = TimeZone.getTimeZone(unmsh.read(nCount));

            unmsh.addObj(timeZone);

            return timeZone;
         }
      };

      s_unmshArray[Text.ARRAY] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            ArrayList list = new ArrayList(nCount);

            unmsh.addObj(list);

            for (int i = 0; i < nCount; ++i)
            {
               list.add(unmsh.unmarshal());
            }

            return list;
         }
      };

      s_unmshArray[Text.SEQUENCE] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller msh) throws IOException
         {
            ArrayList list = new ArrayList(nCount);

            for (int i = 0; i < nCount; ++i)
            {
               list.add(msh.unmarshal());
            }

            return list;
         }
      };

      s_unmshArray[Text.TRANSFER_OBJECT] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            TransferObject tobj = new TransferObject(nCount - 4); // -4 for non-setValue() objects

            unmsh.addObj(tobj);

            tobj.setClassName((String)unmsh.unmarshal());
            tobj.setEventName((String)unmsh.unmarshal());
            tobj.setVersion((short)unmsh.unmarshalLong());

            OID oid = (OID)unmsh.unmarshal();

            if (oid != null)
            {
               tobj.setOID(oid);
            }

            String sKey;

            for (int i = 0; i < nCount; ++i)
            {
               sKey = (String)unmsh.unmarshal();
               tobj.setValue(sKey, unmsh.unmarshal());
            }

            return tobj;
         }
      };

      s_unmshArray[Text.BASIC_OBJECT] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            int nObjIndex = unmsh.m_objectList.size();

            unmsh.addObj(null);

            Symbol className = (Symbol)unmsh.unmarshal();
            Machine machine = unmsh.m_context.getMachine();
            ClassObject classObj = machine.getGlobalEnvironment().findClass(className);
            ObjectOriented bobj = classObj.createObject();

            unmsh.m_objectList.set(nObjIndex, bobj);

            for (int i = 0; i < nCount; i++)
            {
               bobj.setValue(i, unmsh.unmarshal(), machine);
            }

            return bobj;
         }
      };

      s_unmshArray[Text.OID] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            OID oid = new OID(null);

            unmsh.addObj(oid);
            nCount = unmsh.readPrefix(Text.SEQUENCE);

            Object[] valueArray = new Object[nCount];

            for (int i = 0; i < nCount; ++i)
            {
               valueArray[i] = unmsh.unmarshal();
            }

            oid.setValueArray(valueArray);

            return oid;
         }
      };

      s_unmshArray[Text.SYMBOL] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            Symbol sym = Symbol.define(unmsh.read(nCount));

            unmsh.addObj(sym);

            return sym;
         }
      };

      s_unmshArray[Text.PAIR] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            Pair pair = new Pair(null);

            unmsh.addObj(pair);

            pair.setHead(unmsh.unmarshal());
            pair.setTail(unmsh.unmarshal());

            return pair;
         }
      };

      s_unmshArray[Text.BVECTOR] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            byte[] nArray = unmsh.readBase64(nCount);

            unmsh.addObj(nArray);

            return nArray;
         }
      };

      s_unmshArray[Text.CVECTOR] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            char[] cbuf = new char[nCount];

            unmsh.addObj(cbuf);
            unmsh.read(cbuf, 0, cbuf.length);

            for (int i = 0; i < nCount; ++i)
            {
               if (cbuf[i] == '\uFFFF')
               {
                  cbuf[i] = 0;
               }
            }

            return cbuf;
         }
      };

      s_unmshArray[Text.SVECTOR] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            String[] array = new String[nCount];

            unmsh.addObj(array);

            for (int i = 0; i < nCount; ++i)
            {
               array[i] = (String)unmsh.unmarshal();
            }

            return array;
         }
      };

      s_unmshArray[Text.VECTOR] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            Object[] array = new Object[nCount];

            unmsh.addObj(array);

            for (int i = 0; i < nCount; ++i)
            {
               array[i] = unmsh.unmarshal();
            }

            return array;
         }
      };

      s_unmshArray[Text.PRIVILEGE_SET] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            byte[] mask = new byte[(nCount + 1) >> 1];

            if (Binary.read(unmsh.m_reader, mask, 0, nCount) != nCount)
            {
               throw new TextUnmarshallerException("err.rpc.unmshEOF");
            }

            PrivilegeSet privilegeSet = new PrivilegeSet(mask);

            unmsh.addObj(privilegeSet);

            return privilegeSet;
         }
      };

      s_unmshArray[Text.FUNCTION] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            PCodeFunction fun = new PCodeFunction();

            unmsh.addObj(fun);
            fun.code = (char[])unmsh.unmarshal();
            fun.constants = (Object[])unmsh.unmarshal();

            return fun;
         }
      };

      s_unmshArray[Text.MACRO] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            PCodeFunction fun = new PCodeMacro();

            unmsh.addObj(fun);
            fun.code = (char[])unmsh.unmarshal();
            fun.constants = (Object[])unmsh.unmarshal();

            return fun;
         }
      };

      s_unmshArray[Text.REQUEST] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            Request req = new Request();
            int nVersion = unmsh.m_nVersion;

            unmsh.addObj(req);

            req.setNamespace((String)unmsh.unmarshal());
            req.setVersion((String)unmsh.unmarshal());
            req.setAsync(unmsh.unmarshalBoolean());
            req.setCommit(unmsh.unmarshalBoolean());
            req.setLocale((Locale)unmsh.unmarshal());

            if (nVersion >= 2)
            {
               req.setTimeZone((TimeZone)unmsh.unmarshal());
            }

            req.setCorrelator((TransferObject)unmsh.unmarshal());

            if (nVersion <= 3)
            {
               nCount = unmsh.readPrefix(Text.SEQUENCE);
            }

            for (int i = 0; i < nCount; ++i)
            {
               TransferObject tobj = (TransferObject)unmsh.unmarshal();

               if (nVersion <= 3)
               {
                  req.addInvocation(tobj);
               }
               else
               {
                  String sEventName = (String)unmsh.unmarshal();
                  Object args = unmsh.unmarshal();
                  Pair attributes = (Pair)unmsh.unmarshal();

                  req.addInvocation(tobj, sEventName, (args instanceof Collection) ?
                     ((Collection)args).toArray() : (Object[])args, attributes);
               }
            }

            if (nVersion <= 3)
            {
               if (nVersion == 3)
               {
                  nCount = unmsh.readPrefix(Text.SEQUENCE);

                  for (int i = 0; i < nCount; ++i)
                  {
                     Object args = unmsh.unmarshal();

                     req.getInvocation(i).setArguments((args instanceof Collection) ?
                        ((Collection)args).toArray() : (Object[])args);
                  }
               }

               nCount = unmsh.readPrefix(Text.SEQUENCE);

               for (int i = 0; i < nCount; ++i)
               {
                  req.getInvocation(i).setAttributes((Pair)unmsh.unmarshal());
               }
            }

            nCount = unmsh.readPrefix(Text.SEQUENCE);

            for (int i = 0; i < nCount; ++i)
            {
               req.addFilter((TransferObject)unmsh.unmarshal());
            }

            return req;
         }
      };

      s_unmshArray[Text.RESPONSE] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            Response resp = new Response();

            unmsh.addObj(resp);

            nCount = unmsh.readPrefix(Text.SEQUENCE);

            for (int i = 0; i < nCount; ++i)
            {
               resp.addResult(unmsh.unmarshal());
            }

            nCount = unmsh.readPrefix(Text.SEQUENCE);

            for (int i = 0; i < nCount; ++i)
            {
               resp.addEvent((Collection)unmsh.unmarshal());
            }

            return resp;
         }
      };

      s_unmshArray[Text.EXCEPTION] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            int nObjIndex = unmsh.m_objectList.size();

            unmsh.addObj(null);

            String sErrCode = (String)unmsh.unmarshal();
            String sMessage = (String)unmsh.unmarshal();
            int nArgCount = unmsh.readPrefix(Text.SEQUENCE);
            Object[] argArray = (nArgCount == 0) ? null : new Object[nArgCount];

            for (int i = 0; i < nArgCount; ++i)
            {
               argArray[i] = unmsh.unmarshal();
            }

            String sClassName = (String)unmsh.unmarshal();

            GenericException e;

            if (sClassName != null)
            {
               e = new ValidationException(sErrCode, argArray);
            }
            else if (nArgCount != 0)
            {
               e = new GenericException(sErrCode, argArray);
            }
            else
            {
               e = new GenericException(sErrCode, new Object[]{sMessage});
            }

            e.setStackTrace(new StackTraceElement[0]);
            unmsh.m_objectList.set(nObjIndex, e);

            OID oid = (OID)unmsh.unmarshal();
            int nOrdinal = (int)unmsh.unmarshalLong();
            int nAttrCount = unmsh.readPrefix(Text.SEQUENCE);

            if (sClassName != null)
            {
               ValidationException x = (ValidationException)e;

               x.setClassName(sClassName);
               x.setOIDHolder(oid);
               x.setOrdinal(nOrdinal);
            }

            for (int i = 0; i < nAttrCount; i += 2)
            {
               String sName = (String)unmsh.unmarshal();

               ((ValidationException)e).addException(sName, (Throwable)unmsh.unmarshal());
            }

            int nExcCount = unmsh.readPrefix(Text.SEQUENCE);

            for (int i = 0; i < nExcCount; ++i)
            {
               e.addException((Throwable)unmsh.unmarshal());
            }

            return e;
         }
      };

      s_unmshArray[Text.EXPRESSION] = new Unmarshaller()
      {
         public Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException
         {
            Object expr = RPCUtil.parse(new SchemeParser(unmsh.getContext().getMachine().getGlobalEnvironment()),
               unmsh.read(nCount), null);

            unmsh.addObj(expr);

            return expr;
         }
      };
   };

   /**
    * The character stream reader.
    */
   private Reader m_reader;

   /**
    * The working character buffer.
    */
   private char[] m_buffer = new char[32];

   /**
    * The Base64 output stream.
    */
   private DetachableByteArrayOutputStream m_ostream64;

   /**
    * The object reference list.
    */
   private List m_objectList;

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

   // constructors

   /**
    * Creates the unmarshaller with a given runtime context.
    * @param context The runtime context.
    */
   public TextUnmarshaller(Context context)
   {
      m_context = context;
   }

   // operations

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

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

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

   /**
    * Reads the specified number of characters from the input stream.
    * @param nCount The number of characters to read.
    * @return The read string.
    */
   protected String read(int nCount) throws IOException
   {
      if (nCount > m_buffer.length)
      {
         m_buffer = new char[Math.max(nCount, m_buffer.length << 1)];
      }

      read(m_buffer, 0, nCount);

      return new String(m_buffer, 0, nCount);
   }

   /**
    * Reads characters until a character buffer is filled.
    * @param cbuf The character buffer, which on return contains the read characters.
    * @param nStart The start offset of the buffer.
    * @param nEnd The end offset of the buffer.
    */
   protected void read(char[] cbuf, int nStart, int nEnd) throws IOException
   {
      while (nStart < nEnd)
      {
         int nCount = m_reader.read(cbuf, nStart, nEnd - nStart);

         if (nCount < 0)
         {
            if (nStart < nEnd)
            {
               throw new TextUnmarshallerException("err.rpc.unmshEOF");
            }

            break;
         }

         nStart += nCount;
      }
   }

   /**
    * Reads a single character.
    * @return The read character.
    */
   protected char read() throws IOException
   {
      int ch = m_reader.read();

      if (ch < 0)
      {
         throw new TextUnmarshallerException("err.rpc.unmshEOF");
      }

      return (char)ch;
   }

   /**
    * Reads the specified number of Base64-encoded characters from the input stream.
    * @param int nCount The number of characters to read.
    * @return The read byte array.
    */
   protected byte[] readBase64(int nCount) throws IOException
   {
      int nLength = ((nCount + 3) >> 2) * 3;

      if (m_ostream64 == null)
      {
         m_ostream64 = new DetachableByteArrayOutputStream(nLength);
      }
      else
      {
         m_ostream64.reset(nLength);
      }

      long lReadCount = Base64Util.decode(m_reader, m_ostream64, nCount, false);

      if (lReadCount != nCount)
      {
         throw new TextUnmarshallerException("err.rpc.base64");
      }

      if (m_ostream64.size() == m_ostream64.length())
      {
         return m_ostream64.detach();
      }

      return m_ostream64.toByteArray();
   }

   /**
    * Reads a prefix count from the input stream.
    * @param chType The prefix data type. Must match this.
    * @return The prefix count value.
    * @throws TextUnmarshallerException if the prefix data type does not match chType.
    */
   protected int readPrefix(char chType) throws IOException, TextUnmarshallerException
   {
      int nCount = 0;
      int ch = m_reader.read();

      while (ch >= '0' && ch <= '9')
      {
         nCount = nCount * 10 + (ch - '0');
         ch = m_reader.read();
      }

      if (ch != chType &&
         (chType != Text.LONG || ch != Text.INTEGER && ch != Text.DOUBLE && ch != Text.DECIMAL && ch != Text.STRING) &&
         (chType != Text.SEQUENCE || ch != Text.NULL || nCount != 0) &&
         (chType != Text.VERSION || ch != Text.VECTOR && ch != Text.EXCEPTION))
      {
         if (ch < 0)
         {
            throw new TextUnmarshallerException("err.rpc.mshEOF");
         }

         if (chType == Text.VERSION)
         {
            throw new TextUnmarshallerException("err.rpc.mshHeader", new Object[]{Primitive.createCharacter(ch)});
         }

         throw new TextUnmarshallerException("err.rpc.text.unexpectedUnmshType",
            new Object[]{Primitive.createCharacter(ch), Primitive.createCharacter(chType)});
      }

      return nCount;
   }

   /**
    * Adds an object at the end of the object list.
    * @param obj The object to add.
    */
   protected void addObj(Object obj)
   {
      m_objectList.add(obj);
   }

   /**
    * Unmarshals a long value from the input stream.
    * @return The unmarshalled long value.
    */
   protected long unmarshalLong() throws IOException
   {
      return Long.parseLong(read(readPrefix(Text.LONG)));
   }

   /**
    * Unmarshals a boolean value from the input stream.
    * @return The unmarshalled boolean value.
    */
   protected boolean unmarshalBoolean() throws IOException
   {
      return readPrefix(Text.BOOLEAN) != 0;
   }

   /**
    * Unmarshals the next available object from the input stream.
    * @return The unmarshalled object.
    */
   protected Object unmarshal() throws IOException
   {
      int nCount = 0;
      int ch = m_reader.read();

      while (ch >= '0' && ch <= '9')
      {
         nCount = nCount * 10 + (ch - '0');
         ch = m_reader.read();
      }

      if (ch < 0 || ch > 127 || s_unmshArray[ch] == null)
      {
         throw new TextUnmarshallerException("err.rpc.unmshType",
            new Object[]{Primitive.createCharacter(ch)});
      }

      return s_unmshArray[ch].unmarshal(nCount, this);
   }

   /**
    * Deserializes an object from a character stream containing a message.
    * @param reader The character stream reader.
    * @return The deserialized object.
    */
   public Object deserialize(Reader reader) throws IOException, UnmarshallerException
   {
      m_reader = reader;
      m_objectList = new ArrayList(256);

      int nVersion = readPrefix(Text.VERSION);

      if (nVersion < 1 || nVersion > 4)
      {
         throw new TextUnmarshallerException("err.rpc.mshVersion",
            new Object[]{Primitive.createInteger(nVersion)});
      }

      // Only set the detected version if it is supported
      m_nVersion = nVersion;

      Object obj = unmarshal();

      m_reader = null; // free memory not used after unmarshal()
      m_objectList = null; // free memory not used after unmarshal()

      return obj;
   }

   // inner classes

   /**
    * Interface implemented by text unmarshallers.
    */
   private interface Unmarshaller
   {
      /**
       * Unmarshals an object of a specific type from the input stream.
       * @param nCount The count parameter of the text to be unmarshalled.
       * @param msh The text unmarshaller.
       * @return The unmarshalled object.
       */
      Object unmarshal(int nCount, TextUnmarshaller unmsh) throws IOException;
   }
}
TOP

Related Classes of nexj.core.rpc.text.TextUnmarshaller$Unmarshaller

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.