Schimbul de date în implementarea memorată a lui Couchbase între Java și .Net

Încerc să împărtășesc datele stocate într-o cupă de memorie couchbase între Java și .Net.

Am reușit să citesc un set de șir în Java în .Net dar ori de câte ori încerc să citesc un set de șir în .Net în Java rezultatul este Null.

Deci, este posibilă schimbul de date între .Net și Java în coșurile memcache pe un server couchbase.

0

3 răspunsuri

Mulțumesc pentru răspuns, mi-am dat seama.

Motivul .NET este capabil să citească șiruri de caractere setate în Java deoarece biblioteca enyimMemcached interpretează elementul memorat ca un șir, dacă nu recunoaște steagul.

Deci, pentru a putea citi corzile în Java, am creat pur și simplu propriul meu transcoder personalizat prin extinderea SpyObject și așezându-l în depărtare, astfel încât să ignore steagul. Apoi, trec transcoderul personalizat cu apelul meu ca acesta,

_obj = GetMemcachedClient().get(key, new StringTranscoder())

Clasa My StringTranscoder arată astfel,

  /**
 * Copyright (C) 2006-2009 Dustin Sallings
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING
 * IN THE SOFTWARE.
 */

package cachingjavatestapp;

import java.io.IOException;
import net.spy.memcached.CachedData;
import net.spy.memcached.compat.SpyObject;
import net.spy.memcached.transcoders.Transcoder;
import net.spy.memcached.transcoders.TranscoderUtils;

/**
 * Transcoder that serializes and unserializes longs.
 */
public final class StringTranscoder extends SpyObject implements
    Transcoder {

  private static final int FLAGS = 0;

  public boolean asyncDecode(CachedData d) {
    return false;
  }

  public CachedData encode(java.lang.String l) {
        try{
            return new CachedData(FLAGS, l.getBytes("UTF-8"), getMaxSize());
        }
        catch (Exception e){
            return null;
        }
    }


  public String decode(CachedData d) {
        try{
            return new String(d.getData(), "UTF-8");
        }catch(Exception e){
            return null;
        }
  }

  public int getMaxSize() {
    return CachedData.MAX_SIZE;
  }
}

Pentru a putea face schimb de date între .NET și Java. Am folosit pur și simplu biblioteca json.net și biblioteca gson pentru serializarea obiectelor și trecerea șirurilor json la memcached, unde este preluat ca un șir, apoi deserializat folosind bibliotecile json.

Salutari,

0
adăugat

Da, este posibil. În cazul clientului Java, acesta are un "transcoder" construit, care se va ocupa de conversia unui java.lang.String în octeți cu codare corespunzătoare (cred că ar trebui să verific). Partea .NET ar putea citi aceste date înapoi.

În cazul în care lucrurile devin lipicioase, modul în care fiecare bibliotecă client stochează un șir. În protocolul memcached, modul recomandat, dar nu necesar, pentru a face acest lucru este cu steagurile. Provocarea este ca fiecare bibliotecă de clienți să facă drapele în mod diferit, ceea ce dezvoltatorii bibliotecii clienților Couchbase încearcă să rezolve într-un set comun de drapele.

Aceasta înseamnă că, pentru moment, pentru a normaliza modul în care datele sunt stocate între cele două biblioteci de clienți, va trebui să configurați în mod particular biblioteca clientului. De exemplu, Java are transcodori personalizabili și puteți extinde unul dintre transcoderele existente pentru a vă citi/scrie cuvintele de coarde cu steagurile pe care le folosește biblioteca client .NET.

Dați-mi voie să știu ce biblioteci de clienți utilizați și voi actualiza acest lucru cu un exemplu.

0
adăugat
Vă mulțumesc foarte mult pentru răspunsul dvs. Apreciez asta. Folosesc biblioteca Enyim.Caching pe partea .NET și biblioteca spymemcached pe partea Java.
adăugat autor user1435903, sursa

Știu că este o întrebare destul de veche, dar am avut aceeași problemă și am crezut că aș împărtăși soluția mea actuală. Următorul transcoder pentru EnyimMemcached se potrivește mai atent cu modul în care sunt serializate/semnalizate în spymemcached. Evident, acest lucru NU va funcționa dacă încercați să serializați obiecte între .Net și Java; dar vă va permite să lucrați cu mai mult decât șiruri de caractere.

https://github.com/mikeleedev/EnyimMemcached /blob/master/Enyim.Caching/Memcached/Transcoders/SpymemcachedTranscoder.cs

    public class SpymemcachedTranscoder : ITranscoder
    {
        #region Private Members
       //General flags
        private const uint SERIALIZED = 1; //00000000 00000001
        private const uint COMPRESSED = 2; //00000000 00000010 <-- TODO - add support for compression
        private const uint NOFLAG = 0; //00000000 00000000

       //Special flags for specially handled types.
        private const uint SPECIAL_MASK = 0xff00; //11111111 00000000
        private const uint SPECIAL_BOOLEAN = (1 << 8); //00000001 00000000
        private const uint SPECIAL_INT = (2 << 8); //00000010 00000000
        private const uint SPECIAL_LONG = (3 << 8); //00000011 00000000
        private const uint SPECIAL_DATE = (4 << 8); //00000100 00000000
        private const uint SPECIAL_BYTE = (5 << 8); //00000101 00000000
        private const uint SPECIAL_FLOAT = (6 << 8); //00000110 00000000
        private const uint SPECIAL_DOUBLE = (7 << 8); //00000111 00000000
        private const uint SPECIAL_BYTEARRAY = (8 << 8); //00001000 00000000

        private readonly ArraySegment NullArray = new ArraySegment(new byte[0]);
        private readonly DateTime EPOCH_START_DATETIME = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        private readonly SpyMemcachedTranscoderUtils _spyTranscoderUtil = new SpyMemcachedTranscoderUtils(true); 
        #endregion

        #region Serialize/Deserialize
        CacheItem ITranscoder.Serialize(object value)
        {
            return this.Serialize(value);
        }

        object ITranscoder.Deserialize(CacheItem item)
        {
            return this.Deserialize(item);
        }

        protected virtual CacheItem Serialize(object value)
        {
           //raw data is a special case when some1 passes in a buffer (byte[] or ArraySegment)
            if (value is ArraySegment)
            {
               //ArraySegment is only passed in when a part of buffer is being 
               //serialized, usually from a MemoryStream (To avoid duplicating arrays 
               //the byte[] returned by MemoryStream.GetBuffer is placed into an ArraySegment.)
                return new CacheItem(SPECIAL_BYTEARRAY, (ArraySegment)value);
            }

            var tmpByteArray = value as byte[];

           //- or we just received a byte[]. No further processing is needed.
            if (tmpByteArray != null)
            {
                return new CacheItem(SPECIAL_BYTEARRAY, new ArraySegment(tmpByteArray));
            }

            uint flags = NOFLAG;
            ArraySegment data;
            TypeCode code = value == null ? TypeCode.Empty : Type.GetTypeCode(value.GetType());

            switch (code)
            {
                case TypeCode.Empty:
                case TypeCode.DBNull:
                    flags = SPECIAL_BYTEARRAY;
                    data = this.SerializeNull();
                    break;
                case TypeCode.String:
                    flags = NOFLAG;
                    data = this.SerializeString((String)value);
                    break;
                case TypeCode.Int64:
                    flags = SPECIAL_LONG;
                    data = this.SerializeInt64((Int64)value);
                    break;
                case TypeCode.Int32:
                    flags = SPECIAL_INT;
                    data = this.SerializeInt32((Int32)value);
                    break;
                case TypeCode.Boolean:
                    flags = SPECIAL_BOOLEAN;
                    data = this.SerializeBoolean((Boolean)value);
                    break;
                case TypeCode.DateTime:
                    flags = SPECIAL_DATE;
                    data = this.SerializeDateTime((DateTime)value);
                    break;
                case TypeCode.Byte:
                    flags = SPECIAL_BYTE;
                    data = this.SerializeByte((byte)value);
                    break;
                case TypeCode.Single: //float
                    flags = SPECIAL_FLOAT;
                    data = this.SerializeSingle((float)value);
                    break;
                case TypeCode.Double:
                    flags = SPECIAL_DOUBLE;
                    data = this.SerializeDouble((double)value);
                    break;
                default:
                    flags = SERIALIZED;
                    data = this.SerializeObject(value);
                    break;
            }

            //TODO - determine when to apply compression and do it

            return new CacheItem(flags, data);
        }

        protected virtual object Deserialize(CacheItem item)
        {
            if (item.Data.Array == null)
                return null;

            byte[] data = new byte[item.Data.Count];
            Array.Copy(item.Data.Array, item.Data.Offset, data, 0, item.Data.Count);

            //TODO - compression support
            //if ((item.Flags & COMPRESSED) != 0)
            //{
           //   data = Decompress(item.Data);
            //}

            if ((item.Flags & SERIALIZED) != 0)
            {
                return DeserializeObject(data);
            }

            uint flags = item.Flags & SPECIAL_MASK;
            if (flags == NOFLAG)
            {
                return DeserializeString(data);
            }
            else
            {
                switch (flags)
                {
                    case SPECIAL_BYTEARRAY:
                        return data;
                    case SPECIAL_BOOLEAN:
                        return this.DeserializeBoolean(data);
                    case SPECIAL_INT:
                        return this.DeserializeInt32(data);
                    case SPECIAL_LONG:
                        return this.DeserializeInt64(data);
                    case SPECIAL_DATE:
                        return this.DeserializeDateTime(data);
                    case SPECIAL_BYTE:
                        return this.DeserializeByte(data);
                    case SPECIAL_FLOAT:
                        return this.DeserializeSingle(data);
                    case SPECIAL_DOUBLE:
                        return this.DeserializeDouble(data);
                    default:
                        throw new InvalidOperationException(string.Format("SpyTranscoder undecodable with flags: {0}", flags));
                }
            }
        }     
        #endregion

        #region Typed Serialization

        protected virtual ArraySegment SerializeNull()
        {
            return NullArray;
        }

        protected virtual ArraySegment SerializeString(string value)
        {
            return new ArraySegment(Encoding.UTF8.GetBytes((string)value));
        }

        protected virtual ArraySegment SerializeByte(byte value)
        {
            return new ArraySegment(_spyTranscoderUtil.EncodeByte(value));
        }

        protected virtual ArraySegment SerializeBoolean(bool value)
        {
            return new ArraySegment(_spyTranscoderUtil.EncodeBoolean(value));
        }

        protected virtual ArraySegment SerializeInt32(Int32 value)
        {
            return new ArraySegment(_spyTranscoderUtil.EncodeInt(value));
        }

        protected virtual ArraySegment SerializeInt64(Int64 value)
        {
            return new ArraySegment(_spyTranscoderUtil.EncodeLong(value));
        }

        protected virtual ArraySegment SerializeDateTime(DateTime value)
        {
            var epochMilliseconds = (long)(value - EPOCH_START_DATETIME).TotalMilliseconds;
            return new ArraySegment(_spyTranscoderUtil.EncodeLong(epochMilliseconds));
        }

        protected virtual ArraySegment SerializeDouble(Double value)
        {
            return new ArraySegment(_spyTranscoderUtil.EncodeLong(BitConverter.DoubleToInt64Bits(value)));
        }

        protected virtual ArraySegment SerializeSingle(Single value)
        {
            return new ArraySegment(_spyTranscoderUtil.EncodeLong(BitConverter.ToInt32(BitConverter.GetBytes(value), 0)));
        }

        protected virtual ArraySegment SerializeObject(object value)
        {
            using (var ms = new MemoryStream())
            {
                new BinaryFormatter().Serialize(ms, value);

                return new ArraySegment(ms.GetBuffer(), 0, (int)ms.Length);
            }
        }

        #endregion

        #region Typed deserialization

        protected virtual String DeserializeString(byte[] value)
        {
            //return Encoding.UTF8.GetString(value.Array, value.Offset, value.Count);
            return Encoding.UTF8.GetString(value);
        }

        protected virtual Boolean DeserializeBoolean(byte[] value)
        {
            return _spyTranscoderUtil.DecodeBoolean(value);
        }

        protected virtual Int32 DeserializeInt32(byte[] value)
        {
            return _spyTranscoderUtil.DecodeInt(value);
        }

        protected virtual Int64 DeserializeInt64(byte[] value)
        {
            return _spyTranscoderUtil.DecodeLong(value);
        }

        protected virtual DateTime DeserializeDateTime(byte[] value)
        {
            var epochMilliseconds = _spyTranscoderUtil.DecodeLong(value);
            return EPOCH_START_DATETIME.AddMilliseconds(epochMilliseconds);
        }

        protected virtual Double DeserializeDouble(byte[] value)
        {
            return BitConverter.Int64BitsToDouble(_spyTranscoderUtil.DecodeLong(value));
        }

        protected virtual Single DeserializeSingle(byte[] value)
        {
            byte[] bytes = BitConverter.GetBytes(_spyTranscoderUtil.DecodeInt(value));
            return BitConverter.ToSingle(bytes, 0);
        }

        protected virtual Byte DeserializeByte(byte[] data)
        {
            return _spyTranscoderUtil.DecodeByte(data);
        }

        protected virtual object DeserializeObject(byte[] value)
        {
            //using (var ms = new MemoryStream(value.Array, value.Offset, value.Count))
            using (var ms = new MemoryStream(value))
            {
                return new BinaryFormatter().Deserialize(ms);
            }
        }

        #endregion

        #region GZip
        private ArraySegment Compress(ArraySegment data)
        {
            using (var outStream = new MemoryStream())
            {
                using (var compressStream = new GZipStream(outStream, CompressionMode.Compress))
                {
                    using (var inStream = new MemoryStream(data.Array))
                    {
                        inStream.CopyTo(compressStream);
                        return new ArraySegment(outStream.ToArray());
                    }
                }
            }
        }
        private ArraySegment Decompress(ArraySegment data)
        {
            using (var inStream = new MemoryStream(data.Array))
            {
                using (var decompressStream = new GZipStream(inStream, CompressionMode.Decompress))
                {
                    using (var outStream = new MemoryStream())
                    {
                        dec
0
adăugat