/*
 NeoDatis ODB : Native Object Database (odb.info@neodatis.org)
 Copyright (C) 2007 NeoDatis Inc. http://www.neodatis.org

 "This file is part of the NeoDatis ODB open source object database".

 NeoDatis ODB 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.

 NeoDatis ODB 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package org.neodatis.odb.core.layers.layer2.meta;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import org.neodatis.odb.ODBRuntimeException;
import org.neodatis.odb.OID;
import org.neodatis.odb.OdbConfiguration;
import org.neodatis.odb.core.NeoDatisError;
import org.neodatis.odb.core.layers.layer2.instance.IClassPool;
import org.neodatis.tool.wrappers.list.IOdbList;
import org.neodatis.tool.wrappers.list.OdbArrayList;
import org.neodatis.tool.wrappers.map.OdbHashMap;

/**
 * The database meta-model
 * 
 * @author olivier s
 * 
 */
public abstract class MetaModel implements Serializable {

	/** A hash map to speed up the access of classinfo by full class name */
	private Map rapidAccessForUserClassesByName;

	private Map rapidAccessForSystemClassesByName;
	
	private Map rapidAccessForClassesByOid;

	/** A simple list to hold all class infos. It is redundant with the maps, but in some cases, we need sequential access to classes :-(*/
	private IOdbList allClassInfos;
	
	/** to identify if meta model has changed */
	private boolean hasChanged;
	
	protected transient IClassPool classPool;

	public MetaModel() {
		this.classPool = OdbConfiguration.getCoreProvider().getClassPool();
		rapidAccessForUserClassesByName = new OdbHashMap(10);
		rapidAccessForSystemClassesByName = new OdbHashMap(10);
		rapidAccessForClassesByOid = new OdbHashMap(10);
		allClassInfos = new OdbArrayList();
	}

	public void addClass(ClassInfo classInfo) {
		if (classInfo.isSystemClass()) {
			rapidAccessForSystemClassesByName.put(classInfo.getFullClassName(), classInfo);
		} else {
			rapidAccessForUserClassesByName.put(classInfo.getFullClassName(), classInfo);
		}
		rapidAccessForClassesByOid.put(classInfo.getId(), classInfo);
		allClassInfos.add(classInfo);
	}

	public void addClasses(ClassInfoList ciList) {
		Iterator iterator = ciList.getClassInfos().iterator();

		while (iterator.hasNext()) {
			addClass((ClassInfo) iterator.next());
		}
	}
	
	public boolean existClass(String fullClassName) {
		// Check if it is a system class
		boolean exist = rapidAccessForSystemClassesByName.containsKey(fullClassName);

		if (exist) {
			return true;
		}
		// Check if it is user class
		exist = rapidAccessForUserClassesByName.containsKey(fullClassName);
		return exist;
	}

	public String toString() {
		return rapidAccessForUserClassesByName.values() + "/" + rapidAccessForSystemClassesByName.values();
	}

	public IOdbList getAllClasses() {
		return allClassInfos;
	}

	public Collection getUserClasses() {
		return rapidAccessForUserClassesByName.values();
	}

	public Collection getSystemClasses() {
		return rapidAccessForSystemClassesByName.values();
	}

	public int getNumberOfClasses() {
		return allClassInfos.size();
	}

	public int getNumberOfUserClasses() {
		return rapidAccessForUserClassesByName.size();
	}

	public int getNumberOfSystemClasses() {
		return rapidAccessForSystemClassesByName.size();
	}

	/**
	 * Gets the class info from the OID. 
	 * 
	 * @param id
	 * @return the class info with the OID
	 */
	public ClassInfo getClassInfoFromId(OID id) {
		return rapidAccessForClassesByOid.get(id);
	}

	public ClassInfo getClassInfo(String fullClassName, boolean throwExceptionIfDoesNotExist) {
		// Check if it is a system class
		ClassInfo ci = rapidAccessForSystemClassesByName.get(fullClassName);
		if (ci != null) {
			return ci;
		}
		// Check if it is user class
		ci = rapidAccessForUserClassesByName.get(fullClassName);
		if (ci != null) {
			return ci;
		}
		if (throwExceptionIfDoesNotExist) {
			throw new ODBRuntimeException(NeoDatisError.META_MODEL_CLASS_NAME_DOES_NOT_EXIST.addParameter(fullClassName));
		}
		return null;
	}

	/**
	 * 
	 * 
	 * @return The Last class info
	 */
	public ClassInfo getLastClassInfo() {
		return allClassInfos.get(allClassInfos.size()-1);
	}

	/**
	 * This method is only used by the odb explorer. So there is no too much
	 * problem with performance issue.
	 * 
	 * @param ci
	 * @return The index of the class info
	 */
	public int slowGetUserClassInfoIndex(ClassInfo ci) {
		Iterator iterator = rapidAccessForUserClassesByName.values().iterator();
		int i=0;
		ClassInfo ci2 = null;
		while(iterator.hasNext()){
			ci2 = (ClassInfo) iterator.next();
			if(ci2.getId()==ci.getId()){
				return i;
			}
			i++;
		}
		throw new ODBRuntimeException(NeoDatisError.CLASS_INFO_DOES_NOT_EXIST_IN_META_MODEL.addParameter(ci.getFullClassName()));
	}

	/**
	 * @param index The index of the class info to get
	 * @return The class info at the specified index
	 */
	public ClassInfo getClassInfo(int index) {
		return allClassInfos.get(index);
	}
	
	/**
	 * The method is slow nut it is only used in the odb explorer.
	 * @param index
	 * @return
	 */
	public ClassInfo slowGetUserClassInfo(int index) {
		Iterator iterator = rapidAccessForUserClassesByName.values().iterator();
		int i=0;
		ClassInfo ci = null;
		while(iterator.hasNext()){
			ci = (ClassInfo) iterator.next();
			if(i==index){
				return ci;
			}
			i++;
		}
		throw new ODBRuntimeException(NeoDatisError.CLASS_INFO_DOES_NOT_EXIST_IN_META_MODEL.addParameter(" with index "+index));
	}

	public void clear() {
		rapidAccessForSystemClassesByName.clear();
		rapidAccessForUserClassesByName.clear();
		rapidAccessForSystemClassesByName = null;
		rapidAccessForUserClassesByName = null;
		allClassInfos.clear();
	}

	public boolean hasChanged() {
		return hasChanged;
	}

	public void setHasChanged(boolean hasChanged) {
		this.hasChanged = hasChanged;
	}

	public abstract Collection getChangedClassInfo();

	public abstract void resetChangedClasses();
	
	/**
	 * Saves the fact that something has changed in the class (number of
	 * objects or last object oid)
	 * @param ci
	 */
	public abstract void addChangedClass(ClassInfo ci);
	

	public Map getHistory() {
		Map map = new OdbHashMap();
		ClassInfo ci = null;
		Iterator iterator = allClassInfos.iterator();
		while (iterator.hasNext()) {
			ci = iterator.next();
			map.put(ci.getFullClassName(), ci.getHistory());
		}
		return map;
	}
	
	/** Builds a meta model from a list of class infos
	 * 
	 * @param classInfos
	 * @return The new Metamodel
	 */
	public static MetaModel fromClassInfos(IOdbList classInfos){
		MetaModel metaModel = new SessionMetaModel();
		int nbClasses = classInfos.size();
		
		for(int i=0;i getPersistentSubclassesOf(String fullClassName){
		IOdbList result = new OdbArrayList();
		
		Iterator classNames = rapidAccessForUserClassesByName.keySet().iterator();
		String oneClassName = null;
		Class theClass = classPool.getClass(fullClassName);
		Class oneClass = null;
		while(classNames.hasNext()){
			oneClassName = classNames.next();
			if(oneClassName.equals(fullClassName)){
				result.add(getClassInfo(oneClassName, true));
			}else{
				oneClass = classPool.getClass(oneClassName);
				if(theClass.isAssignableFrom(oneClass)){
					result.add(getClassInfo(oneClassName, true));
				}
			}
		}
		
		return result;
	}

	/**
	 * @return
	 */
	public abstract MetaModel duplicate();
}

 

Ads help maintain this website.