InternalMetaRepositoryImpl.java :  » Database-DBMS » jalisto » org » objectweb » jalisto » se » impl » meta » Java Open Source

Java Open Source » Database DBMS » jalisto 
jalisto » org » objectweb » jalisto » se » impl » meta » InternalMetaRepositoryImpl.java
/*
 * Jalisto - JAva LIght STOrage
 * Copyright (C) 2000-2005 Xcalia http://www.xcalia.com
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
 * 
 * Xcalia
 * 71, rue Desnouettes
 * 75014 Paris - France
 * http://www.xcalia.com
 */
package org.objectweb.jalisto.se.impl.meta;

import org.objectweb.jalisto.se.api.Session;
import org.objectweb.jalisto.se.api.query.FieldDescription;
import org.objectweb.jalisto.se.api.*;
import org.objectweb.jalisto.se.api.internal.InternalPhysicalFileAccess;
import org.objectweb.jalisto.se.api.internal.SessionInternal;
import org.objectweb.jalisto.se.api.internal.InternalMetaRepository;
import org.objectweb.jalisto.se.api.internal.InternalFactory;
import org.objectweb.jalisto.se.exception.JalistoException;
import org.objectweb.jalisto.se.exception.SchemaException;
import org.objectweb.jalisto.se.impl.server.IdentityProvider;
import org.objectweb.jalisto.se.impl.InFileAddress;
import org.objectweb.jalisto.se.impl.server.page.ClassPage;
import org.objectweb.jalisto.se.impl.trace.Trace;
import org.objectweb.jalisto.se.JalistoFactory;

import java.util.*;

public class InternalMetaRepositoryImpl implements InternalMetaRepository {

    private InternalMetaRepositoryImpl(JalistoProperties properties) {
        InternalFactory internalFactory = JalistoFactory.getInternalFactory();
        tracer = internalFactory.getTracer(properties);
        tracer.println(Trace.LOGICAL, "MetaRepositoryImpl : create new instance");

        sessions = new ArrayList();

        isMono = properties.isMonoImplementation();

        oidProvider = internalFactory.getIdentityProvider(properties);
        physicalAccess = internalFactory.getInternalPhysicalAccess(properties);
        classPageSize = properties.getClassPageSize();
    }

    public void addSession(SessionInternal session) {
        synchronized (sessions) {
            if (isMono) {
                sessions.clear();
            }
            if (!sessions.contains(session)) {
                sessions.add(session);
            }
        }
    }

    public void removeSession(SessionInternal session) {
        sessions.remove(session);
    }


    public Map getClassMetas() {
        return classMetas;
    }

    public Map getClassTable() {
        return classTable;
    }

    /**
     * ***************************   methods from MetaRepository   ********************************
     */

    public void checkNoActive(String message) {
        for (short i = 0; i < sessions.size(); i++) {
            if (((SessionInternal) sessions.get(i)).currentTransaction().isActive()) {
                throw new SchemaException(message+((SessionInternal) sessions.get(i)).getSessionId());
            }
        }
    }

    public void checkNoSessions(String message) {
        if (!sessions.isEmpty()) {
            throw new JalistoException(message);
        }
    }

    public void closeAllSessions() {
        ArrayList checkedSessions = new ArrayList();
        checkedSessions.addAll(sessions);
        for (short i = 0; i < checkedSessions.size(); i++) {
            SessionInternal s = (SessionInternal) sessions.get(i);
            if (s.currentTransaction().isActive()) {
                s.currentTransaction().rollback();
            }
            if (s.isOpen()) {
                s.closeSession();
            }
        }
    }

    public void defineClass(Session session, ClassDescription classMetaDescription) {
        try {
            ClassDescription oldMeta = getMetaData(classMetaDescription.getClassName());
            if (!oldMeta.equals(classMetaDescription)) {
                throw new SchemaException(
                        "Class " + classMetaDescription.getClassName() + " is already define in base with other metadescription");
            }
            return;
        } catch (SchemaException e) {
            if (!e.getMessage().endsWith("is not define in base")) {
                throw e;
            }
        }
        session.currentTransaction().begin();
        try {
            Object clid = createClidFromClassName(classMetaDescription.getClassName());
            writePersistentClassMetaDescription(clid, (ClassDescriptionImpl) classMetaDescription);
        } catch (SchemaException fse) {
            // class already define
        }
        session.currentTransaction().commit();
    }

    public ClassDescription getMetaData(String className) {
        Object clid = getClidFromClassName(className);
        return getPersistentClassMetaDescription(clid);
    }

    public void removeClass(Session session, String className) {
        checkNoActive(MODIFY_DURING_TRANSACTION_MESSAGE);

        Object sessionId = session.getInternalSession().getSessionId();
        Object clid = classTable.get(className);

        if (clid == null) {
            throw new SchemaException("Class "+className+" is not define in base");
        }

        session.currentTransaction().begin();
        Iterator extent =
                session.getInternalSession().getOidTable().getFloidsFromClid(sessionId, clid, true).iterator();
        while (extent.hasNext()) {
            try {
                session.deleteObjectByOid(extent.next());
            } catch (Exception e) {
                System.out.println("PROBLEM DURING CLEANING OF PERSISTENT INSTANCES");
                e.printStackTrace();
            }
        }

        classTable.remove(className);
        InFileAddress ifa = (InFileAddress) clidIndex.remove(clid);
        ClassDescriptionImpl meta = (ClassDescriptionImpl) classMetas.remove(clid);
        physicalAccess.writeObjectInBase(META_REPOSITORY_IFA, classTable, true);
        physicalAccess.writeObjectInBase(OID_IFA_CLID_INDEX_IFA, clidIndex, true);

        ClassPage classPage = (ClassPage) physicalAccess.readFileObjectAt(ifa);
        classPage.setDataAt(ifa, null);
        physicalAccess.updateFileObject(classPage);

        if (session.getQueryManager() != null) {
            session.getQueryManager().getIndexManager().deleteIndexesOnClass(meta);
        }

        session.currentTransaction().commit();
    }


    public void addField(Session session, String className, FieldDescription fieldDescription) {
        checkNoActive(MODIFY_DURING_TRANSACTION_MESSAGE);

        session.currentTransaction().begin();
        short index = fieldDescription.getIndex();
        Object clid = getClidFromClassName(className);
        ClassDescription meta = getPersistentClassMetaDescription(clid);
        if (meta == null) {
            throw new SchemaException("meta data of class " + className + " null in base");
        }
        if ((index < 0) || (index > meta.getNbrFields())) {
            throw new SchemaException("index " + index + " out of range from 0 to " + meta.getNbrFields());
        }

        Iterator oids = session.getExtent(className).readFully().iterator();
        while (oids.hasNext()) {
            Object oid = oids.next();
            Object[] o = session.readObjectByOid(oid);
            Object[] oo = new Object[o.length + 1];
            for (int i = 0; i < oo.length; i++) {
                if (i < index) {
                    oo[i] = o[i];
                } else if (i == index) {
                    oo[i] = null;
                } else {
                    oo[i] = o[i - 1];
                }
            }
            session.updateObjectByOid(oid, oo);
        }
        meta.addField(fieldDescription);
        writePersistentClassMetaDescription(clid, meta);
        session.currentTransaction().commit();
    }

    public String[] getFieldNames(String className) {
        return getMetaData(className).getFieldNames();
    }

    public void renameField(Session session, String className, String oldFieldName, String newFieldName) {
        checkNoActive(MODIFY_DURING_TRANSACTION_MESSAGE);

        session.currentTransaction().begin();
        Object clid = getClidFromClassName(className);
        int index = getIndex(className, oldFieldName);
        ClassDescription meta = getPersistentClassMetaDescription(clid);

        if (meta == null) {
            throw new SchemaException("meta data of class " + className + " null in base");
        }
        if ((index < 0) || (index > (meta.getNbrFields() - 1))) {
            throw new SchemaException("index " + index + " out of range from 0 to " + (meta.getNbrFields() - 1));
        }

        String[] fieldNames = meta.getFieldNames();
        fieldNames[index] = newFieldName;
        writePersistentClassMetaDescription(clid, meta);
        session.currentTransaction().commit();
    }

    public void removeField(Session session, String className, String fieldName) {
        checkNoActive(MODIFY_DURING_TRANSACTION_MESSAGE);

        session.currentTransaction().begin();
        Object clid = getClidFromClassName(className);
        int index = getIndex(className, fieldName);
        ClassDescription meta = getPersistentClassMetaDescription(clid);

        if (meta == null) {
            throw new SchemaException("meta data of class " + className + " null in base");
        }
        if ((index < 0) || (index > (meta.getNbrFields() - 1))) {
            throw new SchemaException("index " + index + " out of range from 0 to " + (meta.getNbrFields() - 1));
        }

        Iterator oids = session.getExtent(className).readFully().iterator();
        while (oids.hasNext()) {
            Object oid = oids.next();
            Object[] o = session.readObjectByOid(oid);
            Object[] oo = new Object[o.length - 1];
            for (int i = 0; i < oo.length; i++) {
                if (i < index) {
                    oo[i] = o[i];
                } else {
                    oo[i] = o[i + 1];
                }
            }
            session.updateObjectByOid(oid, oo);
        }
        meta.removeField(index);
        writePersistentClassMetaDescription(clid, meta);
        session.currentTransaction().commit();
    }


    public int getIndex(String className, String fieldName) {
        String[] fieldNames = getMetaData(className).getFieldNames();
        for (int i = 0; i < fieldNames.length; i++) {
            if (fieldNames[i].equalsIgnoreCase(fieldName)) {
                return i;
            }
        }
        return -1;
    }


    public Collection getAllClassNames() {
        return classTable.keySet();
    }


    /**
     * *****************************   Page access methods  ****************************************
     */

    public ClassDescription getPersistentClassMetaDescription(Object clid) {
        ClassDescriptionImpl meta = (ClassDescriptionImpl) classMetas.get(clid);
        if (meta == null) {
            meta = internalGetPersistentClassMetaDescription(clid);
            classMetas.put(clid, meta);
        }
        return meta;
    }

    // allocation is done
    public void writePersistentClassMetaDescription(Object clid, ClassDescription metaDescription) {
        tracer.println(Trace.LOGICAL, "MetaRepositoryImpl : writePersistentClassMetaDescription({0}, {1})", clid,
                       metaDescription);
        ((ClassDescriptionImpl)metaDescription).setRepository(this);
        // get ifa of the page where instance is stored
        InFileAddress classIfa = (InFileAddress) clidIndex.get(clid);
        ClassPage classPage = (ClassPage) physicalAccess.readFileObjectAt(classIfa);
        classPage.setDataAt(classIfa, metaDescription);
        physicalAccess.updateFileObject(classPage);
        classMetas.put(clid, metaDescription);
    }

    // allocation is done
    public void writePersistentClassMetaDescription(ClassDescriptionImpl metaDescription) {
        Object clid = getClidFromClassName(metaDescription.getClassName());
        writePersistentClassMetaDescription(clid, metaDescription);
    }

    private void allocateNewClidIfa(Object clid) {
        tracer.println(Trace.LOGICAL, "MetaRepositoryImpl : allocateNewClidIfa({0})", clid);
        if (currentAvalaibleClassPage.getIndex() == (classPageSize - 1)) {
            currentAvalaibleClassPage = new InFileAddress(getNewClassPageAddress());
            ClassPage classPage = new ClassPage(classPageSize);
            classPage.setIfa(currentAvalaibleClassPage);
            physicalAccess.insertFileObject(classPage);
        } else {
            currentAvalaibleClassPage.incrementeFileIndex();
        }
        clidIndex.put(clid, currentAvalaibleClassPage.getClone());
        updateStateInBase(true);
        physicalAccess.writeObjectInBase(OID_IFA_CLID_INDEX_IFA, clidIndex, true);
    }

    private ClassDescriptionImpl internalGetPersistentClassMetaDescription(Object clid) {
        tracer.println(Trace.LOGICAL, "MetaRepositoryImpl : getPersistentClassMetaDescription({0})", clid);
        // get ifa of the system page
        InFileAddress classIfa = (InFileAddress) clidIndex.get(clid);
        ClassPage classPage = (ClassPage) physicalAccess.readFileObjectAt(classIfa);
        // get and return the page info
        ClassDescriptionImpl classMetaDescription = (ClassDescriptionImpl) classPage.getDataAt(classIfa);
        classMetaDescription.setRepository(this);
        return classMetaDescription;
    }

    /**
     * *************************************    CLID METHODS    ********************************************
     */

    public String getClassNameFromClid(Object clid) {
        Iterator keys = classTable.keySet().iterator();
        while (keys.hasNext()) {
            Object key = keys.next();
            if (classTable.get(key).equals(clid)) {
                return (String) key;
            }
        }
        return null;
    }

    public Object getClidFromClassName(String fullClassName) {
        Object result = classTable.get(fullClassName);
        if (result == null) {
            throw new SchemaException("Class " + fullClassName + " is not define in base");
        }
        return result;
    }

    private String getNewClassPageAddress() {
        return "cp" + (classPageIndex++);
    }

    private Object createClidFromClassName(String fullClassName) {
        if (!classTable.containsKey(fullClassName)) {
            Object newClid = oidProvider.getNewClid();
            classTable.put(fullClassName, newClid);
            allocateNewClidIfa(newClid);
            updateStateInBase(true);
            physicalAccess.writeObjectInBase(META_REPOSITORY_IFA, classTable, true);
            return newClid;
        }
        throw new SchemaException("class " + fullClassName + " is already defined in base");
    }

    /**
     * *******************************     INITIALIZATION     ***************************************
     */

    private void init(short classPageSize) {
        classTable = new HashMap();
        clidIndex = new Hashtable();
        classPageIndex = 0;
        currentAvalaibleClassPage = new InFileAddress(getNewClassPageAddress());
        currentAvalaibleClassPage.setIndex(-1);

        ClassPage firstClassPage = new ClassPage(classPageSize);
        firstClassPage.setIfa(currentAvalaibleClassPage);
        physicalAccess.insertFileObject(firstClassPage);

        updateStateInBase(false);
        physicalAccess.writeObjectInBase(META_REPOSITORY_IFA, classTable, false);
        physicalAccess.writeObjectInBase(OID_IFA_CLID_INDEX_IFA, clidIndex, false);

        classMetas = new HashMap();
    }

    private void getStateFromBase() {
        classTable = (Map) physicalAccess.readFileObjectAt(META_REPOSITORY_IFA).getData();

        clidIndex = (Map) physicalAccess.readFileObjectAt(OID_IFA_CLID_INDEX_IFA).getData();

        Object[] datas = (Object[]) physicalAccess.readFileObjectAt(MR_STATE_IFA).getData();
        currentAvalaibleClassPage = (InFileAddress) datas[0];
        classPageIndex = ((Integer) datas[1]).intValue();

        classMetas = new HashMap();
        Iterator clids = classTable.values().iterator();
        while (clids.hasNext()) {
            Object clid = clids.next();
            ClassDescription meta = getPersistentClassMetaDescription(clid);
            classMetas.put(clid, meta);
        }
    }

    public synchronized void updateStateInBase(boolean isUpdate) {
        Object[] datas = new Object[2];
        datas[0] = currentAvalaibleClassPage;
        datas[1] = new Integer(classPageIndex);
        physicalAccess.writeObjectInBase(MR_STATE_IFA, datas, isUpdate);
    }

    public static InternalMetaRepositoryImpl getAnMetaRepository(JalistoProperties properties) {
        InternalMetaRepositoryImpl repository = new InternalMetaRepositoryImpl(properties);
        try {
            // load it from base
            repository.getStateFromBase();
        } catch (Exception e) {
            repository.init(properties.getClassPageSize());
        }
        return repository;
    }

    private ArrayList sessions;
    private IdentityProvider oidProvider;
    private InternalPhysicalFileAccess physicalAccess;

    private Map classMetas;         // clid -> classMeta
    private Map classTable;         // classname -> clid
    private Map clidIndex;          // clid -> class meta's ifa

    private InFileAddress currentAvalaibleClassPage;
    private int classPageIndex;
    private int classPageSize;

    private boolean isMono;
    private Trace tracer;


    private static final InFileAddress META_REPOSITORY_IFA = new InFileAddress("metarep");
    private static final InFileAddress OID_IFA_CLID_INDEX_IFA = new InFileAddress("clid");
    private static final InFileAddress MR_STATE_IFA = new InFileAddress("mrstate");


    public static final String MODIFY_DURING_TRANSACTION_MESSAGE = "Try to modify schema during active transaction : ";
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.