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

src-xml.org.neodatis.odb.xml.XMLImporter Maven / Gradle / Ivy

There is a newer version: 1.9.30.689
Show newest version
/*
 NeoDatis ODB : Native Object Database ([email protected])
 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.xml;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.SAXParserFactory;

import org.neodatis.odb.ODB;
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.meta.AbstractObjectInfo;
import org.neodatis.odb.core.layers.layer2.meta.ArrayObjectInfo;
import org.neodatis.odb.core.layers.layer2.meta.ClassAttributeInfo;
import org.neodatis.odb.core.layers.layer2.meta.ClassInfo;
import org.neodatis.odb.core.layers.layer2.meta.CollectionObjectInfo;
import org.neodatis.odb.core.layers.layer2.meta.EnumNativeObjectInfo;
import org.neodatis.odb.core.layers.layer2.meta.MapObjectInfo;
import org.neodatis.odb.core.layers.layer2.meta.MetaModel;
import org.neodatis.odb.core.layers.layer2.meta.NonNativeNullObjectInfo;
import org.neodatis.odb.core.layers.layer2.meta.NonNativeObjectInfo;
import org.neodatis.odb.core.layers.layer2.meta.NullNativeObjectInfo;
import org.neodatis.odb.core.layers.layer2.meta.ODBType;
import org.neodatis.odb.core.layers.layer2.meta.ObjectReference;
import org.neodatis.odb.core.layers.layer2.meta.SessionMetaModel;
import org.neodatis.odb.core.layers.layer3.IStorageEngine;
import org.neodatis.odb.core.oid.OIDFactory;
import org.neodatis.odb.impl.core.layers.layer3.engine.Dummy;
import org.neodatis.odb.impl.core.layers.layer3.engine.StorageEngineConstant;
import org.neodatis.odb.impl.tool.ObjectTool;
import org.neodatis.tool.ConsoleLogger;
import org.neodatis.tool.DLogger;
import org.neodatis.tool.ILogger;
import org.neodatis.tool.wrappers.list.IOdbList;
import org.neodatis.tool.wrappers.list.OdbArrayList;
import org.neodatis.tool.wrappers.map.OdbHashMap;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

public class XMLImporter implements ContentHandler {

	private static final String LOG_ID = "XMLImporter";

	private static final int STATE_UNKNOWN = 0;

	private static final int STATE_CLASS_INFO = 1;

	private static final int STATE_OBJECTS = 2;

	private static final int STATE_OBJECT = 3;

	private static final int STATE_ATTRIBUTE = 4;

	private static final int STATE_ATTRIBUTE_COLLECTION = 5;

	private static final int STATE_ATTRIBUTE_ARRAY = 6;

	private static final int STATE_ATTRIBUTE_MAP = 7;

	private static final int STATE_ODB = 8;

	private IStorageEngine storageEngine;

	private MetaModel metaModel;

	private ClassInfo ci;

	private IOdbList classAttributeInfo;

	private int state;

	private NonNativeObjectInfo nnoi;

	private List objectInfos;

	private OID objectId;

	private OID objectClassId;

	private List attributeCollection;

	private String realClassName;

	private Map attributeMap;

	private Object[] attributeArray;

	private int arrayIndex;

	private int currentLevel;

	private OID maxObjectId;

	/**
	 * The file format version . Information available since 1.9 release, If not
	 * present in the xml, we assume file format version is less that 9
	 */
	private int fileFormatVersion;

	/** When reading an attribute, this field is used to keep its id */
	private int attributeId;

	private int nbObjects;

	private ILogger externalLogger;

	public XMLImporter(IStorageEngine storageEngine) {
		this.storageEngine = storageEngine;
	}

	public XMLImporter(ODB odb) {
		this.storageEngine = Dummy.getEngine(odb);
	}

	public void importFile(String directory, String filename) throws Exception {

		String fullFileName = directory + "/" + filename;

		info("Importing file " + fullFileName);
		SAXParserFactory factory = SAXParserFactory.newInstance();
		factory.setNamespaceAware(false);

		XMLReader xmlReader = factory.newSAXParser().getXMLReader();

		// This class also implements the LexicalHandler and DeclHandler
		// extensions

		// xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler",this);
		// xmlReader.setProperty("http://xml.org/sax/properties/declaration-handler",this);

		xmlReader.setContentHandler(this);
		xmlReader.parse(fullFileName);

		storageEngine.commit();
		// storageEngine.close();

	}

	public void setDocumentLocator(Locator locator) {
	}

	public void startDocument() throws SAXException {
	}

	public void endDocument() throws SAXException {
	}

	public void startPrefixMapping(String prefix, String uri) throws SAXException {
	}

	public void endPrefixMapping(String prefix) throws SAXException {
	}

	public void startElement(String uri, String localName, String tagName, Attributes attributes) throws SAXException {
		currentLevel++;
		try {

			if (tagName.equals(XmlTags.TAG_ODB)) {
				state = STATE_ODB;
				try {
					maxObjectId = OIDFactory.buildObjectOID(Long.parseLong(attributes.getValue(XmlTags.ATTRIBUTE_MAX_OID)));
					reserveIds(maxObjectId, false);
				} catch (IOException e) {
					throw new ODBRuntimeException(NeoDatisError.XML_RESERVING_IDS.addParameter(maxObjectId), e);
				}
				// Try to get version
				try {
					String version = attributes.getValue(XmlTags.ATTRIBUTE_FILE_FORMAT_VERSION);
					// If file version tag is not present, we have an old xml
					// file format
					if (version == null || version.length() == 0) {
						fileFormatVersion = StorageEngineConstant.VERSION_8;
					} else {
						fileFormatVersion = Integer.parseInt(version);
					}
				} catch (Exception e) {
					// file version tag is not present, we have an old xml file
					// format
					fileFormatVersion = StorageEngineConstant.VERSION_8;
				}
				return;
			}

			if (tagName.equals(XmlTags.TAG_METAMODEL)) {
				metaModel = new SessionMetaModel();
				info("Importing Meta Model");
				return;
			}
			if (tagName.equals(XmlTags.TAG_CLASS)) {
				nbObjects = 0;
				state = STATE_CLASS_INFO;
				String classId = attributes.getValue(XmlTags.ATTRIBUTE_ID);
				String name = attributes.getValue(XmlTags.ATTRIBUTE_NAME);

				// The IF is to manage old xml version
				if (fileFormatVersion >= StorageEngineConstant.CURRENT_FILE_FORMAT_VERSION) {
					ci = new ClassInfo(name, "");
				} else {
					// In the old version, class name and package name are in
					// two different tags
					// And we don't have extra info
					String packageName = attributes.getValue(XmlTags.ATTRIBUTE_PACKAGE_NAME);
					String fullClassName = packageName + "." + name;
					ci = new ClassInfo(fullClassName, "");
				}
				ci.setId(OIDFactory.buildClassOID(Long.parseLong(classId)));
				classAttributeInfo = new OdbArrayList();
				info(". Importing class " + ci.getFullClassName());
				return;
			}
			if (tagName.equals(XmlTags.TAG_ATTRIBUTE) && state == STATE_CLASS_INFO) {
				String id = attributes.getValue(XmlTags.ATTRIBUTE_ID);
				String name = attributes.getValue(XmlTags.ATTRIBUTE_NAME);
				String type = attributes.getValue(XmlTags.ATTRIBUTE_TYPE);
				String isEnum = attributes.getValue(XmlTags.ATTRIBUTE_IS_ENUM);

				ClassAttributeInfo cai = new ClassAttributeInfo(Integer.parseInt(id), name, type, null);

				// Enums must be managed in different way. They are native
				// objects by with a specific class
				// So we first create the cai with ODBType.ENUM.getName() so
				// that NeoDatis
				// undestands it is a native object and then sets the right enum
				// class name
				if (isEnum != null && isEnum.equals("true")) {
					cai = new ClassAttributeInfo(Integer.parseInt(id), name, ODBType.ENUM.getName(), null);
					ODBType odbType = cai.getAttributeType().copy();
					odbType.setName(type);
					cai.setAttributeType(odbType);
					cai.setFullClassName(type);
				}

				if (cai.getAttributeType().isArray()) {
					String arrayOfWhat = attributes.getValue(XmlTags.ATTRIBUTE_ARRAY_OF);
					cai.getAttributeType().setSubType(ODBType.getFromName(arrayOfWhat));
					// copy the odb type to avoid another cai uses the same reference
					cai.setAttributeType(cai.getAttributeType().copy());
				}
				classAttributeInfo.add(cai);
				return;
			}

			if (tagName.equals(XmlTags.TAG_OBJECTS)) {
				state = STATE_OBJECTS;
				objectInfos = new ArrayList();
				return;
			}
			if (tagName.equals(XmlTags.TAG_OBJECT) && state == STATE_OBJECTS) {
				state = STATE_OBJECT;
				String sObjectId = attributes.getValue(XmlTags.ATTRIBUTE_OID);
				objectId = OIDFactory.buildObjectOID(Long.parseLong(sObjectId));
				String sObjectClassId = attributes.getValue(XmlTags.ATTRIBUTE_CLASS_ID);
				objectClassId = OIDFactory.buildClassOID(Long.parseLong(sObjectClassId));
				nnoi = new NonNativeObjectInfo(metaModel.getClassInfoFromId(objectClassId));
				nnoi.setOid(objectId);
				nbObjects++;
				if (nbObjects % 1000 == 0) {
					info(". " + nbObjects + " objects");
				}
				return;
			}
			if (tagName.equals(XmlTags.TAG_ATTRIBUTE) && state == STATE_OBJECT) {
				state = STATE_ATTRIBUTE;
				String id = attributes.getValue(XmlTags.ATTRIBUTE_ID);
				attributeId = Integer.parseInt(id);
				String name = attributes.getValue(XmlTags.ATTRIBUTE_NAME);
				String value = attributes.getValue(XmlTags.ATTRIBUTE_VALUE);
				String encoding = OdbConfiguration.getDatabaseCharacterEncoding();
				if (value != null) {
					if (encoding == null || encoding.equals(StorageEngineConstant.NO_ENCODING)) {
						value = URLDecoder.decode(value);
					} else {
						value = URLDecoder.decode(value, encoding);
					}
				}
				String objectRefId = attributes.getValue(XmlTags.ATTRIBUTE_OBJECT_REF_ID);
				String sIsNull = attributes.getValue(XmlTags.ATTRIBUTE_NULL);
				boolean isNull = false;
				if (sIsNull != null) {
					isNull = true;
				}
				ClassInfo ci = metaModel.getClassInfoFromId(objectClassId);
				if (ci == null) {
					System.out.println("ci is null");
				}
				ClassAttributeInfo cai = ci.getAttributeInfoFromId(attributeId);
				if (cai == null) {
					System.out.println("cai is null");
				}
				ODBType type = cai.getAttributeType();

				if ((type.isArrayOrCollection() || type.isMap()) && !isNull) {
					nnoi.setAttributeValue(attributeId, new NullNativeObjectInfo(type.getId()));
					if (type.isCollection()) {
						state = STATE_ATTRIBUTE_COLLECTION;
					}
					if (type.isArray()) {
						state = STATE_ATTRIBUTE_ARRAY;
					}
					if (type.isMap()) {
						state = STATE_ATTRIBUTE_MAP;
					}
				} else {

					AbstractObjectInfo aoi = null;
					if (objectRefId != null) {
						aoi = new ObjectReference(OIDFactory.buildObjectOID(Long.parseLong(objectRefId)));
						nnoi.setAttributeValue(attributeId, aoi);
					} else {
						if (isNull) {
							if (type.isNonNative()) {
								nnoi.setAttributeValue(attributeId, new NonNativeNullObjectInfo(ci));
							} else {
								nnoi.setAttributeValue(attributeId, new NullNativeObjectInfo(type.getId()));
							}
						} else {
							// when it is an enum, attributeCi (class info) is
							// the real enum class
							ClassInfo attributeCi = null;
							if (type.isEnum()) {
								attributeCi = metaModel.getClassInfo(cai.getFullClassname(), true);
							}
							aoi = ObjectTool.stringToObjectInfo(type.getId(), value, ObjectTool.ID_CALLER_IS_XML, attributeCi);
							nnoi.setAttributeValue(attributeId, aoi);
						}
					}
				}
				return;
			}
			if (tagName.equals(XmlTags.TAG_COLLECTION) && state == STATE_ATTRIBUTE_COLLECTION) {
				int size = Integer.parseInt(attributes.getValue(XmlTags.ATTRIBUTE_SIZE));
				attributeCollection = new ArrayList(size);
				realClassName = attributes.getValue(XmlTags.ATTRIBUTE_REAL_CLASS_NAME);
				return;
			}
			if (tagName.equals(XmlTags.TAG_ARRAY) && state == STATE_ATTRIBUTE_ARRAY) {
				int size = Integer.parseInt(attributes.getValue(XmlTags.ATTRIBUTE_SIZE));
				attributeArray = new Object[size];
				arrayIndex = 0;
				realClassName = attributes.getValue(XmlTags.ATTRIBUTE_ARRAY_OF);
				return;
			}
			if (tagName.equals(XmlTags.TAG_MAP) && state == STATE_ATTRIBUTE_MAP) {
				int size = Integer.parseInt(attributes.getValue(XmlTags.ATTRIBUTE_SIZE));
				attributeMap = new OdbHashMap(size);
				realClassName = attributes.getValue(XmlTags.ATTRIBUTE_REAL_CLASS_NAME);
				return;
			}

			if (tagName.equals(XmlTags.TAG_ELEMENT) && state == STATE_ATTRIBUTE_COLLECTION) {
				String objectRefId = attributes.getValue(XmlTags.ATTRIBUTE_OBJECT_REF_ID);
				if (objectRefId != null) {
					attributeCollection.add(new ObjectReference(OIDFactory.buildObjectOID(Long.parseLong(objectRefId))));
				} else {
					String value = attributes.getValue(XmlTags.ATTRIBUTE_VALUE);
					ODBType type = ODBType.getFromName(attributes.getValue(XmlTags.ATTRIBUTE_TYPE));
					attributeCollection.add(ObjectTool.stringToObjectInfo(type.getId(), value, ObjectTool.ID_CALLER_IS_XML, null));
				}
				return;
			}
			if (tagName.equals(XmlTags.TAG_ELEMENT) && state == STATE_ATTRIBUTE_ARRAY) {
				String objectRefId = attributes.getValue(XmlTags.ATTRIBUTE_OBJECT_REF_ID);
				if (objectRefId != null) {
					attributeArray[arrayIndex++] = new ObjectReference(OIDFactory.buildObjectOID(Long.parseLong(objectRefId)));
				} else {
					String value = attributes.getValue(XmlTags.ATTRIBUTE_VALUE);
					ODBType type = ODBType.getFromName(realClassName);
					attributeArray[arrayIndex++] = ObjectTool.stringToObjectInfo(type.getId(), value, ObjectTool.ID_CALLER_IS_XML, null);
				}
				return;
			}
			if (tagName.equals(XmlTags.TAG_ELEMENT) && state == STATE_ATTRIBUTE_MAP) {
				String keyRefId = attributes.getValue(XmlTags.ATTRIBUTE_KEY_ID);
				String objectRefId = attributes.getValue(XmlTags.ATTRIBUTE_OBJECT_REF_ID);
				Object key = null;
				Object value = null;

				if (keyRefId != null) {
					key = new ObjectReference(OIDFactory.buildObjectOID(Long.parseLong(keyRefId)));
				} else {
					String v = attributes.getValue(XmlTags.ATTRIBUTE_KEY_VALUE);
					String keyType = attributes.getValue(XmlTags.ATTRIBUTE_KEY_TYPE);
					ODBType type = ODBType.getFromName(keyType);
					key = ObjectTool.stringToObjectInfo(type.getId(), v, ObjectTool.ID_CALLER_IS_XML, null);
					
					if(type.isEnum()){
						String ciId = attributes.getValue(XmlTags.ATTRIBUTE_ENUM_CLASS_OID);
						EnumNativeObjectInfo anoi = (EnumNativeObjectInfo) key;
						anoi.setEnumClassInfo(metaModel.getClassInfoFromId(OIDFactory.buildClassOID(Long.parseLong(ciId))));
					}
				}

				if (objectRefId != null) {
					value = new ObjectReference(OIDFactory.buildObjectOID(Long.parseLong(objectRefId)));
				} else {
					String v = attributes.getValue(XmlTags.ATTRIBUTE_VALUE);
					ODBType type = ODBType.getFromName(attributes.getValue(XmlTags.ATTRIBUTE_VALUE_TYPE));
					value = ObjectTool.stringToObjectInfo(type.getId(), v, ObjectTool.ID_CALLER_IS_XML, null);
				}
				attributeMap.put(key, value);
				return;
			}
		} catch (Exception e) {
			throw new ODBRuntimeException(NeoDatisError.IMPORT_ERROR
					.addParameter(storageEngine.getBaseIdentification().getIdentification()), e);
		} finally {
		}
	}

	private void reserveIds(OID maxOid, boolean onlyFirstBlock) throws IOException {

		long nbOids = maxOid.getObjectId();
		info("Allocating " + nbOids + " OIDs (Object IDs)");
		if (onlyFirstBlock) {
			if (nbOids > OdbConfiguration.getNB_IDS_PER_BLOCK()) {
				nbOids = OdbConfiguration.getNB_IDS_PER_BLOCK();
			}
		} else {
			if (nbOids <= OdbConfiguration.getNB_IDS_PER_BLOCK()) {
				// No more than one id block, nothing to do
				return;
			}
			// nbOids = nbOids - Configuration.getNB_IDS_PER_BLOCK();

		}
		storageEngine.getObjectWriter().getIdManager().reserveIds(nbOids);

	}

	public void endElement(String uri, String localName, String tagName) throws SAXException {
		try {
			if (tagName.equals(XmlTags.TAG_CLASS)) {
				ci.setAttributes(classAttributeInfo);
				metaModel.addClass(ci);
				state = STATE_UNKNOWN;
				if (OdbConfiguration.isDebugEnabled(LOG_ID)) {
					DLogger.debug("Class " + ci.getFullClassName() + " created");
				}
				// info(". Class "+ci.getFullClassName()+" imported.");
				return;
			}
			if (tagName.equals(XmlTags.TAG_METAMODEL)) {
				state = STATE_UNKNOWN;
				// try {
				info("Persisting Meta Model");
				storageEngine.setMetaModel(metaModel);
				// Now that meta model has been stored, lets write the end of
				// the
				// ids
				// reserveIds(maxObjectId, false);
				// } catch (IOException e) {
				// throw new ODBRuntimeException(Error.XML_SETTING_META_MODEL,
				// e);
				// }
				info(". Meta Model persisted. " + metaModel.getNumberOfClasses() + " classes");
				return;
			}
			if (tagName.equals(XmlTags.TAG_OBJECT) && state == STATE_OBJECT) {
				try {
					// The last parameter is used to indicate that it is a new
					// object
					// The false : object are not written in transaction
					storageEngine.getObjectWriter().writeNonNativeObjectInfo(nnoi.getOid(), nnoi, -1, false, true);
					if (OdbConfiguration.isDebugEnabled(LOG_ID)) {
						info("Object of type " + nnoi.getClassInfo().getFullClassName() + " with oid " + nnoi.getOid() + " created");
					}
				} catch (Exception e) {
					throw new ODBRuntimeException(NeoDatisError.INTERNAL_ERROR.addParameter("in XmlImporter.endElement.writeObjectInfo"), e);
				}
				state = STATE_OBJECTS;
				return;
			}
			if (tagName.equals(XmlTags.TAG_ATTRIBUTE) && state == STATE_ATTRIBUTE) {
				state = STATE_OBJECT;
				return;
			}
			if (tagName.equals(XmlTags.TAG_COLLECTION) && state == STATE_ATTRIBUTE_COLLECTION) {
				CollectionObjectInfo coi = new CollectionObjectInfo(attributeCollection);
				coi.setRealCollectionClassName(realClassName);
				nnoi.setAttributeValue(attributeId, coi);
				state = STATE_ATTRIBUTE;
				attributeCollection = null;
				attributeId = -1;
				return;
			}
			if (tagName.equals(XmlTags.TAG_ARRAY) && state == STATE_ATTRIBUTE_ARRAY) {
				ArrayObjectInfo aoi = new ArrayObjectInfo(attributeArray);
				aoi.setRealArrayComponentClassName(realClassName);
				// copy the odb type 
				aoi.setOdbType(aoi.getOdbType().copy());
				aoi.getOdbType().setSubType(ODBType.getFromName(realClassName));
				nnoi.setAttributeValue(attributeId, aoi);
				state = STATE_ATTRIBUTE;
				attributeArray = null;
				attributeId = -1;
				return;
			}
			if (tagName.equals(XmlTags.TAG_MAP) && state == STATE_ATTRIBUTE_MAP) {
				MapObjectInfo moi = new MapObjectInfo(attributeMap, realClassName);
				nnoi.setAttributeValue(attributeId, moi);
				state = STATE_ATTRIBUTE;
				attributeMap = null;
				attributeId = -1;
				return;
			}
		} finally {
			currentLevel--;
		}
	}

	public void characters(char[] ch, int start, int length) throws SAXException {

	}

	public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
	}

	public void processingInstruction(String target, String data) throws SAXException {
	}

	public void skippedEntity(String name) throws SAXException {
	}

	public void setExternalLogger(ILogger logger) {
		this.externalLogger = logger;
	}
	public void logToConsole() {
		this.externalLogger = new ConsoleLogger();
	}


	protected void info(Object o) {
		if (externalLogger != null) {
			externalLogger.info(o);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy