/* * Copyright (c) 2010-2012, 2015 Eike Stepper (Berlin, Germany) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Ibrahim Sallam - initial API and implementation */ package org.eclipse.emf.cdo.server.internal.objectivity.db; import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.cdo.server.internal.objectivity.ObjectivityStore; import org.eclipse.emf.cdo.server.internal.objectivity.bundle.OM; import org.eclipse.emf.cdo.server.internal.objectivity.mapper.ITypeMapper; import org.eclipse.emf.cdo.server.internal.objectivity.mapper.ObjyMapper; import org.eclipse.emf.cdo.server.internal.objectivity.schema.ObjyArrayListId; import org.eclipse.emf.cdo.server.internal.objectivity.schema.ObjyArrayListString; import org.eclipse.emf.cdo.server.internal.objectivity.schema.ObjyBase; import org.eclipse.emf.cdo.server.internal.objectivity.schema.ObjyFeatureMapArrayList; import org.eclipse.emf.cdo.server.internal.objectivity.schema.ObjyProxy; import org.eclipse.emf.cdo.server.internal.objectivity.schema.ObjyResourceList; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcorePackage; import com.objy.as.app.d_Attribute; import com.objy.as.app.d_Class; import com.objy.as.app.d_Module; import java.util.HashMap; import java.util.Map; /** * Wrapper for the AS schema code with caching of the wrapped classes. This class need to be reseted by the * ObjectivityStore doDeactivate(). * * @author ibrahim */ public class ObjySchema { private static final ContextTracer TRACER_DEBUG = new ContextTracer(OM.DEBUG, ObjySchema.class); // static HashMap<String, d_Class> mapOfCacheClasses = new HashMap<String, d_Class>(); private static HashMap<String, ObjyClass> mapOfObjyClasses = new HashMap<String, ObjyClass>(); private static HashMap<String, EClass> mapOfEClasses = new HashMap<String, EClass>(); private static HashMap<EClass, EClass> visitedClasses = new HashMap<EClass, EClass>(); private static HashMap<EClass, EClass> visitedStructureOnlyClasses = new HashMap<EClass, EClass>(); private static Map<String, String> packageNameMapping = new HashMap<String, String>(); private static d_Module topModule = null; public static void resetCache() { topModule = null; mapOfObjyClasses.clear(); mapOfEClasses.clear(); visitedClasses.clear(); visitedStructureOnlyClasses.clear(); } public static ObjyClass getObjyClass(String name) { ObjyClass classObject = mapOfObjyClasses.get(name); if (classObject == null) { d_Class newClass = getTopModule().resolve_class(name); // EClass eClass = getEClass(store, name); // IS:TEMP if (newClass == null) { TRACER_DEBUG.trace("NULL..... dClass for " + name); } classObject = new ObjyClass(newClass); mapOfObjyClasses.put(name, classObject); } return classObject; } public static d_Module getTopModule() { if (topModule == null) { topModule = d_Module.top_level(); } return topModule; } /** * Originally in EProposedManager. */ static public String getObjectivityClassName(EClassifier eClassifier) { return formObjectivityClassName(eClassifier, false); } /** * Originally in EProposedManager */ static String formObjectivityClassName(EClassifier eClassifier, boolean onlyStructure) { if (eClassifier == EcorePackage.eINSTANCE.getEObject()) { return "ooObj"; } // same class names might exist in different nsUri. String nsURI = eClassifier.getEPackage().getNsURI(); // // get the hash string for uniqueness. // String nsURIHash = new Integer(Math.abs(nsURI.hashCode())).toString(); String objyPackageName = getObjyPackageName(nsURI); if (onlyStructure) { // return "oo_" + eClassifier.getEPackage().getName() + "_" + eClassifier.getName() + "ST"; // return "oo_" + nsURIHash + "_" + eClassifier.getEPackage().getNsPrefix() + "_" + eClassifier.getName() + "_ST"; return objyPackageName + ":" + eClassifier.getName() + "_ST"; } // return "oo_" + eClassifier.getEPackage().getName() + "_" + eClassifier.getName(); // return "oo_" + nsURIHash + "_" + eClassifier.getEPackage().getNsPrefix() + "_" + eClassifier.getName(); return objyPackageName + ":" + eClassifier.getName(); } static public void setPackageNameMapping(String name1, String name2) { if (packageNameMapping.get(name1) == null) { packageNameMapping.put(name1, name2); } } static public String getPackageNameMapping(String key) { return packageNameMapping.get(key); } /** * Originally in EProposedManager * * @param ePackage */ static public void registerEPackage(EPackage ePackage) { for (EClassifier eClass : ePackage.getEClassifiers()) { if (eClass instanceof EClass) { getOrCreate(eClass.eClass()); } } } /** * @param eClass * @return ObjyClass */ static public ObjyClass getOrCreate(EClass eClass) { String className = getObjectivityClassName(eClass); ObjyClass objyClass = mapOfObjyClasses.get(className); if (objyClass != null) { return objyClass; } // create the ObjyClass and hash it. synchronized (getTopModule()) { // System.out.println("OBJY: finding class '" + className + "' in objy schema."); d_Class dClass = getTopModule().resolve_class(className); // System.out.println("OBJY:... got d_Class:" + dClass); // TODO - evolving classes is partially implemented, only adding attributes is // supported. if (dClass == null) { objyClass = createObjyClass(eClass); } else if (!isSameClass(dClass, eClass)) { objyClass = evolveObjyClass(eClass); } else { objyClass = new ObjyClass(dClass/* , eClass */); } if (objyClass == null) { throw new RuntimeException("Cannot retrieved " + eClass.getName() + " class from Objy schema as:" + className); } String asClassName = objyClass.getASClassName(); mapOfObjyClasses.put(asClassName, objyClass); mapOfEClasses.put(asClassName, eClass); } return objyClass; } /** * @param eClass * @return */ private static ObjyClass createObjyClass(EClass eClass) { try { String className = getObjectivityClassName(eClass); // System.out.println("OBJY: calling createObjyClassSchema for class: " + className); createObjyClassSchema(eClass, false); getTopModule().activate_proposals(true, true); // getTopModule().activate_proposals(true); // System.out.println("OBJY: resolving class '" + className + "' in objy schema."); d_Class dClass = getTopModule().resolve_class(className); // IS:TEMP if (dClass == null) { TRACER_DEBUG.trace("NULL..... dClass for " + className); } ObjyClass objyClass = new ObjyClass(dClass/* , eClass */); return objyClass; } catch (Throwable throwable) { throwable.printStackTrace(); } return null; } public static ObjyClass evolveObjyClass(EClass eClass) { try { String className = getObjectivityClassName(eClass); evolveObjyClassSchema(eClass, false); getTopModule().activate_proposals(true, true); // getTopModule().activate_proposals(true); // System.out.println("OBJY: resolving class '" + className + "' in objy schema."); d_Class dClass = getTopModule().resolve_class(className); // IS:TEMP. if (dClass == null) { TRACER_DEBUG.trace("NULL..... dClass for " + className); } ObjyClass objyClass = new ObjyClass(dClass/* , eClass */); return objyClass; } catch (Throwable throwable) { throwable.printStackTrace(); } return null; } /** * This function creates the schema in Objectivity, if the class is being proposed or already exist no action is * happening. */ static void createObjyClassSchema(EClass eClass, boolean onlyStructure) { HashMap<EClass, EClass> hashMap = onlyStructure ? visitedStructureOnlyClasses : visitedClasses; if (hashMap.containsKey(eClass)) { return; } hashMap.put(eClass, eClass); String className = formObjectivityClassName(eClass, onlyStructure); d_Class dClass = getTopModule().resolve_class(className); if (dClass != null) { return; } // check if the class has been proposed before if (getTopModule().resolve_proposed_class(className) == null) { if (TRACER_DEBUG.isEnabled()) { TRACER_DEBUG.trace("Creating new class: " + className); } // start schema creation. // System.out.println("OBJY: starting schema creation for class: " + className); ObjyClassProposed proposedClass = new ObjyClassProposed(getTopModule(), eClass, onlyStructure); proposedClass.propose(); } } /** * @param eClass * @param itrOnlyStructure */ static void evolveObjyClassSchema(EClass eClass, boolean onlyStructure) { String className = formObjectivityClassName(eClass, onlyStructure); // check if the class has been proposed before if (getTopModule().resolve_proposed_class(className) == null) { d_Class dClass = getTopModule().resolve_class(className); TRACER_DEBUG.trace("Evolving class: " + className); // start schema evolution. // System.out.println("OBJY: starting schema creation for class: " + className); ObjyClassProposed proposedClass = new ObjyClassProposed(getTopModule(), eClass, onlyStructure); proposedClass.evolve(dClass); } } // From EProposedManager... // For now check only the name of the attribute // It only check from EMF to Objectivity... not the reverse // TODO - see if we can do full cycle schema changes. static boolean isSameClass(d_Class dClass, EClass eClass) { // Look at the hierarchy for (EClass superType : eClass.getESuperTypes()) { getOrCreate(superType); } for (EStructuralFeature feature : eClass.getEStructuralFeatures()) { if (!(feature instanceof EAttribute || feature instanceof EReference)) { continue; } ITypeMapper mapper = ObjyMapper.INSTANCE.getTypeMapper(feature); if (mapper == null) { continue; } // identify any missing attribute. d_Attribute dAttr = dClass.resolve_attribute(feature.getName()); if (dAttr == null) { return false; } /**** * TODO - actiavte this code, once ITypeMapper.validate() is implemented. ITypeMapper attributeMapper = * ObjyMapper.INSTANCE.getTypeMapper(feature); if (attributeMapper.validate(dAttr, feature) == false) { if * (TRACER_DEBUG.isEnabled()) { TRACER_DEBUG.trace("Feature " + feature.getName() + " for object " + * eClass.getName() + " changed "); } attributeMapper.validate(dAttr, feature); return false; } ****/ } return true; } // /** // * From EProposedManager. // */ // void ensureEClassExist(EClass eClass, boolean onlyStructure) // { // HashMap<EClass, EClass> hashMap = onlyStructure ? visitedStructureOnlyClass : visitedClass; // if (hashMap.containsKey(eClass)) // { // return; // } // // hashMap.put(eClass, eClass); // String nameClass = getObjectivityClassName(eClass, onlyStructure); // d_Class ooClass = getTopModule().resolve_class(nameClass); // // if (ooClass != null && isSameClass(ooClass, eClass)) // { // return; // } // // if (module.resolve_proposed_class(nameClass) == null) // { // EProposedClass proposedClass = new EProposedClass(module, eClass, onlyStructure); // proposedClass.propose(this, ooClass); // } // } // /** // * From EProposedManager. // */ // void ensureEClassExist(EClass eClass) // { // ensureEClassExist(eClass, false); // } public static EClass getEClass(ObjectivityStore store, ObjyClass objyClass) { String className = objyClass.getASClassName(); return getEClass(store, className); } public static EClass getEClass(ObjectivityStore store, String className) { // String className = objyObject.getASClass().name(); // System.out.println("OBJY: getEClass(store, " + className +")"); EClass eClass = mapOfEClasses.get(className); if (eClass == null) { // the format is "<some_URI_name_used_as_package_name>:className" String[] splits = className.split(":"); // get the mapping to the nsURI. CDOPackageRegistry registry = store.getRepository().getPackageRegistry(); String nsURI = getPackageNameMapping(splits[0]); EPackage packageObject = registry.getEPackage(nsURI); if (packageObject == null) { throw new RuntimeException("Package not found " + splits[1] + " for class name " + className); } eClass = (EClass)packageObject.getEClassifier(splits[splits.length - 1]); mapOfEClasses.put(className, eClass); } // else // { // System.out.println("***OBJY: getEClass(cached): " + eClass); // } return eClass; } /*** * identify if the class is of type Resource. TODO - why we need to pass the store, can't we keep the info we need for * the package mapping here?!!! */ public static boolean isResource(ObjectivityStore store, ObjyClass objyClass) { EClass eClass = getEClass(store, objyClass); if (eClass == EresourcePackage.Literals.CDO_RESOURCE || eClass == EresourcePackage.Literals.CDO_RESOURCE_NODE || eClass == EresourcePackage.Literals.CDO_RESOURCE_FOLDER) { return true; } return false; } /*** * Build initial schema for some collection classes. */ public static void createBaseSchema() { ObjyArrayListId.buildSchema(); ObjyFeatureMapArrayList.buildSchema(); ObjyProxy.buildSchema(); ObjyArrayListString.buildSchema(); ObjyBase.buildSchema(); ObjyResourceList.buildSchema(); } public static String getObjyPackageName(String packageURI) { String name = ""; boolean first = true; // parse the URI, remove "http://" and replace each "." with "_" String[] splits = packageURI.split("://"); for (String strValue : splits) { if (strValue.equals("http")) { continue; } if (!first) { name = name.concat("_"); } else { first = false; } name = name.concat(strValue); } name = name.replace("/", "."); name = name.replace(".", "_"); return name; } }