Java tutorial
/** * <copyright> * * Copyright (c) 2005, 2006, 2007, 2008 Springsite BV (The Netherlands) 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: * Martin Taal - Initial API and implementation * * </copyright> * * $Id: ERuntime.java,v 1.20 2010/02/04 11:03:02 mtaal Exp $ */ package org.eclipse.emf.teneo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.ExtendedMetaData; import org.eclipse.emf.teneo.classloader.ClassLoaderResolver; import org.eclipse.emf.teneo.classloader.StoreClassLoadException; import org.eclipse.emf.teneo.ecore.EModelResolver; import org.eclipse.emf.teneo.util.StoreUtil; /** * The ERuntime contains references to EPackages which are persistable, i.e. are persisted. * * It is used to compute information related to concrete class - eclass mapping, interface to * concrete class, references for cross reference computation, contained computations. * * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> * @version $Revision: 1.20 $ */ public class ERuntime extends EModelResolver { /** The logger */ private static Log log = LogFactory.getLog(ERuntime.class); /** The singleton instance */ public static final ERuntime INSTANCE = new ERuntime(); /** The list of epackages processed here */ private final ArrayList<EPackage> epackages = new ArrayList<EPackage>(); /** Count of times that an epackage got registered */ private final ArrayList<Integer> registrationCount = new ArrayList<Integer>(); /** The mapping from concrete classes to eclass and back */ private final HashMap<Class<?>, EClass> concreteToEClass = new HashMap<Class<?>, EClass>(); private final HashMap<Class<?>, EClass> interfaceToEClass = new HashMap<Class<?>, EClass>(); private final HashMap<EClassifier, Class<?>> eclassifierToConcrete = new HashMap<EClassifier, Class<?>>(); /** The list of topclasses/interfaces */ private final ArrayList<Class<?>> topClasses = new ArrayList<Class<?>>(); /** The list of contained classes/interfaces */ private final ArrayList<Class<?>> containedClasses = new ArrayList<Class<?>>(); /** Remove an epackage from the internal lists */ public void removeEPackages(List<EPackage> ePackages) { for (EPackage ePackage : ePackages) { epackages.remove(ePackage); } // recompute everything computeConcreteInstanceMapping(); computeContainedClasses(); } /** Register the epackages */ @Override public synchronized void register(EPackage[] epacks) { for (int i = 0; i < epacks.length; i++) { if (!epackages.contains(epacks[i])) { epackages.add(epacks[i]); } } computeConcreteInstanceMapping(); computeContainedClasses(); } /** Resets the maps/lists */ @Override public void clear() { epackages.clear(); containedClasses.clear(); concreteToEClass.clear(); interfaceToEClass.clear(); eclassifierToConcrete.clear(); topClasses.clear(); } /** * Computes which classes are contained and which are non-contained. Method must be called after * the computeReferers method! */ private void computeContainedClasses() { topClasses.clear(); containedClasses.clear(); for (int i = 0; i < epackages.size(); i++) { final EPackage epack = epackages.get(i); if (ignorePackage(epack)) { continue; } for (EClassifier eclassifier : epack.getEClassifiers()) { if (!(eclassifier instanceof EClass)) { continue; } final EClass eclass = (EClass) eclassifier; // bit ugly compare on name, but document root should be ignored // otherwise everything is contained if (ExtendedMetaData.INSTANCE.isDocumentRoot(eclass)) { continue; } for (EReference eref : eclass.getEReferences()) { if (!eref.isContainment()) { continue; } final Class<?> toClass = eref.getEType().getInstanceClass(); if (!containedClasses.contains(toClass)) { containedClasses.add(toClass); } } } } // and then when it is not contained add it to the contained list for (Class<?> clazz : interfaceToEClass.keySet()) { if (containedClasses.contains(clazz)) { continue; // already determined so continue } if (isSelfOrSuperContained(clazz, containedClasses)) { containedClasses.add(clazz); } else { final EClass eClass = getEClass(clazz); // remove all the abstract types // see bugzilla 220106 if (eClass == null || !eClass.isAbstract()) { topClasses.add(clazz); } } } // topclasses are cleaned because they are used to query and otherwise // different queries would return overlapping results (because of // polymor.) cleanList(topClasses); cleanList(containedClasses); } /** * Walks through a interface inheritance structure and determines if a superclass is contained * if so then the class is added to the containedclasses */ private boolean isSelfOrSuperContained(Class<?> checkClass, ArrayList<Class<?>> containedClasses) { // assert (checkClass.isInterface()); if (containedClasses.contains(checkClass)) { return true; } final Class<?>[] interfaces = checkClass.getInterfaces(); for (Class<?> element : interfaces) { if (isSelfOrSuperContained(element, containedClasses)) { return true; } } return false; } /** Returns the list of topclasses */ public Class<?>[] getTopClasses() { return topClasses.toArray(new Class[topClasses.size()]); } /** Return the list of interfaces */ public Set<Class<?>> getAllInterfaces() { return interfaceToEClass.keySet(); } /** Returns all concrete classes */ public Set<Class<?>> getAllConcreteClasses() { return concreteToEClass.keySet(); } /** * Retains only the root parent class in a list, so if an entry in the list as a parent in the * same list then the child is deleted from the list */ private void cleanList(ArrayList<Class<?>> list) { final ArrayList<Class<?>> toRemove = new ArrayList<Class<?>>(); for (Class<?> clazz : list) { if (clazz == null) { continue; } final Class<?>[] supers = clazz.getInterfaces(); for (Class<?> element : supers) { if (list.contains(element)) { toRemove.add(clazz); break; } } } list.removeAll(toRemove); } /** Determines concrete impl classes for each eclass */ private void computeConcreteInstanceMapping() { concreteToEClass.clear(); eclassifierToConcrete.clear(); interfaceToEClass.clear(); // walk through all the epackages for (int i = 0; i < epackages.size(); i++) { final EPackage epack = epackages.get(i); if (ignorePackage(epack)) { if (log.isDebugEnabled()) { log.debug("Not determining concrete classes for package " + epack.getName()); } continue; } if (log.isDebugEnabled()) { log.debug("Determining concrete classes for package " + epack.getName()); } for (EClassifier eclassifier : epack.getEClassifiers()) { if (!(eclassifier instanceof EClass)) { continue; } final Object instance = create((EClass) eclassifier); if (instance != null && !(instance instanceof DynamicEObjectImpl)) { eclassifierToConcrete.put(eclassifier, instance.getClass()); concreteToEClass.put(instance.getClass(), (EClass) eclassifier); } if (eclassifier.getInstanceClass() != null) { interfaceToEClass.put(eclassifier.getInstanceClass(), (EClass) eclassifier); } } } // packaged in an extra arraylist to prevent concurrent modification // exception. final List<Class<?>> classes = new ArrayList<Class<?>>(concreteToEClass.keySet()); for (Class<?> clz : classes) { addAbstractSupers(clz); } } /** * Walks up the class hierarchy and adds the superclasses to the concrete-interface mapping * class sets */ private void addAbstractSupers(Class<?> clazz) { // clazz is null or not an eobject if (clazz == null || !EObject.class.isAssignableFrom(clazz)) { return; } // if already been here then go on for the superclasses if (concreteToEClass.get(clazz) != null) { addAbstractSupers(clazz.getSuperclass()); return; } // new one, find all its interfaces final Class<?>[] interf = clazz.getInterfaces(); for (Class<?> element : interf) { if (EObject.class.isAssignableFrom(element)) { final EClass eclass = interfaceToEClass.get(element); concreteToEClass.put(clazz, eclass); eclassifierToConcrete.put(eclass, clazz); } } } /* * (non-Javadoc) * * @see org.eclipse.emf.teneo.jpox.emf.IEMFDataStore#getEPackages() */ @Override public synchronized EPackage[] getEPackages() { return epackages.toArray(new EPackage[epackages.size()]); } /** Returns true if the epackage is registered here */ @Override public synchronized boolean isRegistered(EPackage epackage) { return epackages.contains(epackage); } /** Convenience method to easily determine which packages should be ignored */ private static boolean ignorePackage(EPackage epack) { return false; // } // if (epack instanceof XMLTypePackageImpl) { // return true; // ignore this // } // if (epack instanceof EcorePackageImpl) { // return true; // ignore this // } // return false; } /** Returns the instanceclass for a passed interface */ public synchronized Class<?> getInstanceClass(Class<?> interf) { final EClass eclass = interfaceToEClass.get(interf); if (eclass == null) { throw new TeneoException("No eclass for interf " + interf.getName()); } return getJavaClass(eclass); } /** Returns the instanceclass for a passed eclass */ @Override public synchronized Class<?> getJavaClass(EClassifier eclassifier) { if (eclassifier instanceof EClass) { final EClass eclass = (EClass) eclassifier; if (eclass.isInterface()) { return eclass.getInstanceClass(); } } return eclassifierToConcrete.get(eclassifier); } /** Returns the interface class for a passed eclass */ @Override public synchronized Class<?> getJavaInterfaceClass(EClass eclass) { return eclass.getInstanceClass(); } /** Returns true if the passed EClass has a javaClass representation. */ @Override public synchronized boolean hasImplementationClass(EClassifier eclassifier) { return null != getJavaClass(eclassifier); } /** Returns null */ @Override public synchronized Object create(EClass eclass) { // abstract instance classes are added later if (eclass.isAbstract() || eclass.isInterface()) { return null; } // Check if the class is persistable try { return EcoreUtil.create(eclass); } catch (Exception e) { // log but do nothing because this happens when we try to create an // object // with an invalid classifier, which is a eclass! if (log.isDebugEnabled()) { log.debug("The classifier: " + eclass.getName() + " is not a valid eclass"); } return null; } } /** Get the eclass for a certain class */ @Override public synchronized EClass getEClass(Class<?> clazz) { if (clazz.isInterface()) { return interfaceToEClass.get(clazz); } return concreteToEClass.get(clazz); } /** Get the eclass for a certain class name */ public synchronized EClass getEClass(String classname) { try { return getEClass(ClassLoaderResolver.classForName(classname)); } catch (StoreClassLoadException e) { log.debug("Failed to retreive ECLass for name: " + classname); return null; } } /** * Returns the structural feature for a certain field and object comby. Null is returned if * nothing is found */ public synchronized EStructuralFeature getStructuralFeature(Class<?> clazz, String FieldName) { final EClass eclass = getEClass(clazz); if (eclass == null) { return null; } return StoreUtil.getEStructuralFeature(eclass, FieldName); } /** * Returns the list of EMF interfaces which are contained. Only the topmost interface in a class * hierarchy is returned. This can be used to automatically create the econtainer field * mappings. * * Note that multiple classes in one inheritance structure can be present. */ public synchronized Class<?>[] getContainedInterfaces() { return containedClasses.toArray(new Class[containedClasses.size()]); } /* * (non-Javadoc) * * @see org.eclipse.emf.teneo.ecore.EModelResolver#getAllClassesAndInterfaces() */ @Override public synchronized List<Class<?>> getAllClassesAndInterfaces() { final List<Class<?>> result = new ArrayList<Class<?>>(); result.addAll(getAllConcreteClasses()); result.addAll(getAllInterfaces()); return result; } }