All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nustaq.serialization.FSTClazzNameRegistry Maven / Gradle / Ivy

Go to download

A fast java serialization drop in-replacement and some serialization based utils such as Structs and OffHeap Memory.

There is a newer version: 3.0.4-jdk17
Show newest version
/*
 * Copyright 2014 Ruediger Moeller.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.nustaq.serialization;

import org.nustaq.offheap.structs.unsafeimpl.FSTStructFactory;
import org.nustaq.serialization.util.FSTIdentity2IdMap;
import org.nustaq.serialization.util.FSTObject2IntMap;
import org.nustaq.serialization.util.FSTUtil;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created with IntelliJ IDEA.
 * User: ruedi
 * Date: 10.11.12
 * Time: 00:34
 *
 * maps classnames => id and vice versa.
 *
 * FSTConfiguration holds a parent containing default mappings (e.g. created by
 * registerClass ). A stream instance then creates a temporary instance to record/id encode
 * classes dynamically during serialization. This way a class name is only written once per
 * object graph.
 *
 * This class is thread safe,
 *
 */
public class FSTClazzNameRegistry {

    public static final int LOWEST_CLZ_ID = 3;
    public static final int FIRST_USER_CLZ_ID = 1000;

    FSTIdentity2IdMap clzToId;
    FSTClazzInfo idToClz[];
    FSTClazzNameRegistry parent;
    int classIdCount = LOWEST_CLZ_ID;

    public FSTClazzNameRegistry(FSTClazzNameRegistry par) {
        parent = par;
        if ( parent != null ) {
            classIdCount = Math.max(FIRST_USER_CLZ_ID,parent.classIdCount+1);
            clzToId = new FSTIdentity2IdMap(13);
            idToClz = new FSTClazzInfo[31];
        } else {
            clzToId = new FSTIdentity2IdMap(FSTObject2IntMap.adjustSize(400));
            idToClz = new FSTClazzInfo[200];
        }
    }

    public void clear() {
        if ( clzToId.size() > 0 ) {
            clzToId.clear();
            //idToClz.clear();
        }
        classIdCount = LOWEST_CLZ_ID;
        if ( parent != null ) {
            classIdCount = Math.max(FIRST_USER_CLZ_ID,parent.classIdCount+1);
        }
    }

    // for read => always increase handle (wg. replaceObject)
    public void registerClass(Class c,FSTConfiguration conf) {
        if ( getIdFromClazz(c) != Integer.MIN_VALUE ) {
            return;
        }
        registerClassNoLookup(c,null,conf);
    }

    private void registerClassNoLookup(Class c,FSTClazzInfo cli, FSTConfiguration conf) {
        addClassMapping(c, classIdCount++,cli,conf);
    }

    public void registerClass( Class c, int code, FSTConfiguration conf) {
        if ( getIdFromClazz(c) != Integer.MIN_VALUE ) {
            return;
        }
        addClassMapping(c, code, null,conf);
    }

    protected void addClassMapping( Class c, int id, FSTClazzInfo clInfo, FSTConfiguration conf ) {
        clzToId.put(c, id);
        if (clInfo==null)
            clInfo = conf.getCLInfoRegistry().getCLInfo(c, conf);
        if (idToClz.length<=id)
        {
            final FSTClazzInfo[] tmp = new FSTClazzInfo[id + 100];
            System.arraycopy(idToClz,0,tmp,0,idToClz.length);
            idToClz = tmp;
        }
        idToClz[id] = clInfo;
        if ( parent == null ) {
            clInfo.setClzId(id);
        }
    }

    public int getIdFromClazz(Class c) {
        int res = Integer.MIN_VALUE;
        if ( parent != null ) {
            res = parent.getIdFromClazz(c);
        }
        if ( res == Integer.MIN_VALUE ) {
            res = clzToId.get(c);
        }
        return res;
    }

    public void encodeClass(FSTEncoder out, FSTClazzInfo ci) throws IOException {
        int clzId = ci.getClzId();
        if ( clzId >= 0 ) {
            out.writeFShort((short) clzId); // > 2 !!
        } else {
            if ( ci.isAsciiNameShortString) {
                final Class aClass = ci.getClazz();
                int clid = getIdFromClazz(aClass);
                if ( clid != Integer.MIN_VALUE ) {
                    out.writeFShort((short) clid); // > 2 !!
                } else {
                    // ugly hack, also making assumptions about
                    // on how the encoder works internally
                    final byte[] bufferedName = ci.getBufferedName();
                    out.writeFShort((short) 1); // no direct cl id ascii enc
                    out.writeFInt((char) bufferedName.length);
                    out.writeRawBytes(bufferedName,0,bufferedName.length);
                    registerClassNoLookup(aClass,ci,ci.conf);
                }
            } else {
                encodeClass(out,ci.getClazz());
            }
        }
    }

    public void encodeClass(FSTEncoder out, Class c) throws IOException {
        int clid = getIdFromClazz(c);
        if ( clid != Integer.MIN_VALUE ) {
            out.writeFShort((short) clid); // > 2 !!
        } else {
            encodeClassName(out, c, out.getConf() );
        }
    }

    private void encodeClassName(FSTEncoder out, Class c, FSTConfiguration conf) throws IOException {
        out.writeFShort((short) 0); // no direct cl id
        out.writeStringUTF(c.getName());
        registerClassNoLookup(c,null,conf);
    }

    public FSTClazzInfo decodeClass(FSTDecoder in, FSTConfiguration conf) throws IOException, ClassNotFoundException {
        short c = in.readFShort();
        if ( c < LOWEST_CLZ_ID ) {
            // full class name
            String clName;
            if ( c==0) {
                clName = in.readStringUTF();
            }
            else {
                clName = in.readStringAsc();
            }
            Class cl = classForName(clName,conf);
            final FSTClazzInfo clInfo = conf.getCLInfoRegistry().getCLInfo(cl, conf);
            registerClassNoLookup(cl,clInfo,conf);
            return clInfo;
        } else {
            FSTClazzInfo aClass = getClazzFromId(c);
            if ( aClass == null ) {
                throw new RuntimeException("unable to find class for code "+c);
            }
            return aClass;
        }
    }

    HashMap classCache = new HashMap(200);
    AtomicBoolean classCacheLock = new AtomicBoolean(false);
    public Class classForName(String clName, FSTConfiguration conf) throws ClassNotFoundException {
        if ( parent != null ) {
            return parent.classForName(clName,conf);
        }
        try {
            while (!classCacheLock.compareAndSet(false, true)) ;
            Class res = classCache.get(clName);
            if (res == null) {
                try {
                    res = Class.forName(clName, false, conf.getClassLoader());
                } catch (Throwable th) {
                    if (clName.endsWith("_Struct")) // hack to define struct proxys on the fly if sent from another process
                    {
                        try {
                            clName = clName.substring(0, clName.length() - "_Struct".length());
                            Class onHeapStructClz = classCache.get(clName);
                            if (onHeapStructClz == null)
                                onHeapStructClz = Class.forName(clName, false, conf.getClassLoader() );
                            res = FSTStructFactory.getInstance().getProxyClass(onHeapStructClz);
                        } catch (Throwable th1) {
                            FSTUtil.rethrow(th1);
                        }
                    } else if ( clName.endsWith("_ActorProxy") ) {
                        // same as above for actors. As there is a custom serializer defined for actors, just instantiate
                        // actor clazz
                        String clName0 = clName;
                        clName = clName.substring(0, clName.length() - "_ActorProxy".length());
                        Class actorClz = classCache.get(clName);
                        if (actorClz == null) {
                            try {
                                actorClz = Class.forName(clName, false, conf.getClassLoader());
                            } catch (ClassNotFoundException clf) {
                                if ( conf.getLastResortResolver() != null ) {
                                    Class aClass = conf.getLastResortResolver().getClass(clName0);
                                    if ( aClass != null )
                                        return aClass;
                                }
                                FSTUtil.rethrow(clf);
                            }
                        }
                        return actorClz;
                    } else {
                        if ( conf.getLastResortResolver() != null ) {
                            Class aClass = conf.getLastResortResolver().getClass(clName);
                            if ( aClass != null )
                                return aClass;
                        }
                        throw new RuntimeException("class not found CLASSNAME:" + clName + " loader:"+conf.getClassLoader(), th);
                    }
                }
                if (res != null) {
                    classCache.put(clName, res);
                }
            }
            return res;
        } finally {
            classCacheLock.set(false);
        }
    }

    public void registerClazzFromOtherLoader( Class cl ) {
        while( ! classCacheLock.compareAndSet(false,true) );
        classCache.put(cl.getName(),cl);
        classCacheLock.set(false);
    }

    public FSTClazzInfo getClazzFromId(int c) {
        FSTClazzInfo res = null;
        if ( parent != null ) {
            res = parent.getClazzFromId(c);
        }
        if ( res == null ) {
            if ( c < 0 || c >= idToClz.length )
                return null;
            return idToClz[c];
        } else {
            return res;
        }
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy