/******************************************************************************* * Copyright (c) 2001, 2006 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ /* * Created on Oct 24, 2003 * * To change the template for this generated file go to * Window>Preferences>Java>Code Generation>Code and Comments */ package org.eclipse.jst.j2ee.ejb.internal.util; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.WeakHashMap; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.jem.java.Field; import org.eclipse.jem.java.JavaClass; import org.eclipse.jem.java.JavaVisibilityKind; import org.eclipse.jst.j2ee.ejb.CMPAttribute; import org.eclipse.jst.j2ee.ejb.ContainerManagedEntity; import org.eclipse.jst.j2ee.ejb.EjbFactory; import org.eclipse.jst.j2ee.ejb.EjbPackage; import org.eclipse.jst.j2ee.ejb.internal.impl.ContainerManagedEntityImpl; /** * @author jlanuti * * To change the template for this generated type comment go to * Window>Preferences>Java>Code Generation>Code and Comments */ public class CMPKeySynchronizationAdapter extends AdapterImpl { public static final String ADAPTER_TYPE = CMPKeySynchronizationAdapter.class.getName(); private boolean initialized = false; protected ContainerManagedEntity cmp = null; private boolean isUpdating = false; private boolean isEnabled = true; private static WeakHashMap<CMPKeySynchronizationAdapter, Object> unresolvedCMPAttributesToFlush = new WeakHashMap<CMPKeySynchronizationAdapter, Object>(); /** * Default constructor */ public CMPKeySynchronizationAdapter(ContainerManagedEntity cmp) { super(); this.cmp = cmp; } /** * If the keyAttributes list is empty, try to reflect * the keyAttributes from the fields of the primaryKey class. */ public void initializeKeyAttributes() { if(cmp == null || initialized) return; //Disable notifications while we initialize cmp.eSetDeliver(false); try { Resource res = cmp.eResource(); if(res == null) return; boolean cachedIsModified = res.isModified(); try { // Handle primkeyfield scenario if (cmp.getPrimKeyField()!=null) initializeForPrimKey(); // Handle compound key scenario else initializeForCompoundKey(); } finally { res.setModified(cachedIsModified); } } finally { cmp.eSetDeliver(true); initialized = true; } } protected void initializeForPrimKey() { // Ensure the key attributes list contains only the primKeyField attribute if (!(getKeyAttributes().size()==1 && getKeyAttributes().contains(cmp.getPrimKeyField()))) primKeyFieldChanged(cmp.getPrimKeyField()); } protected void initializeForCompoundKey() { List keys = getKeyAttributes(); // clear key list keys.clear(); //ensure the key class is not null JavaClass keyClass = cmp.getPrimaryKey(); if (keyClass == null) return; keyClass.eAdapters().add(this); // reflect key fields into key attributes list List keyFields = keyClass.getFieldsExtended(); if(keyFields.size() == 0){ unresolvedCMPAttributesToFlush.put(this, null); }else{ unresolvedCMPAttributesToFlush.remove(this); } for (int i = 0; i < keyFields.size(); i++) { Field field = (Field) keyFields.get(i); if (field.getJavaVisibility() == JavaVisibilityKind.PUBLIC_LITERAL) { //only public fields CMPAttribute keyAttribute = cmp.getPersistentAttribute(field.getName()); if (keyAttribute != null) keys.add(keyAttribute); } } } public static void flushUnresolvedKeyAttributesOnCleanBuild(){ Iterator itr = unresolvedCMPAttributesToFlush.keySet().iterator(); while(itr.hasNext()){ CMPKeySynchronizationAdapter curAdapter = (CMPKeySynchronizationAdapter)itr.next(); curAdapter.initialized = false; curAdapter.initializeKeyAttributes(); } } @Override public void notifyChanged(Notification notification) { if (isUpdating || !isEnabled) return; //we don't want to react to our own changes try { isUpdating = true; EClass featureClass = ((EObject)notification.getNotifier()).eClass(); if (EjbPackage.eINSTANCE.getContainerManagedEntity().equals(featureClass)) { switch (notification.getFeatureID(ContainerManagedEntity.class)) { // handle if cmp attribute is updated, added, removed case EjbPackage.CONTAINER_MANAGED_ENTITY__PERSISTENT_ATTRIBUTES : { handleCMPAttributeEvent(notification); break; } // handle the key attributes list is updated programatically case EjbPackage.CONTAINER_MANAGED_ENTITY__KEY_ATTRIBUTES : { handleCMPAttributeEvent(notification); break; } // handle if the key class is changed,added, removed case EjbPackage.CONTAINER_MANAGED_ENTITY__PRIMARY_KEY : { handleKeyClassEvent(notification); break; } // handle prim key field sets, adds, removes case EjbPackage.CONTAINER_MANAGED_ENTITY__PRIM_KEY_FIELD : { handlePrimKeyFieldEvent(notification); break; } } } else if (EjbPackage.eINSTANCE.getCMPAttribute().equals(featureClass)) { switch (notification.getFeatureID(CMPAttribute.class)) { // handle a set or change of an attribute name case (EjbPackage.CMP_ATTRIBUTE__NAME) : { handleCMPAttributeRenameEvent((CMPAttribute)notification.getNotifier(), notification.getOldValue()); break; } } } } finally { // restore initial notification state isUpdating = false; } } /** * @param attribute */ private void handleCMPAttributeRenameEvent(CMPAttribute attribute, Object oldValue) { // if renamed attribute was in key and is not anymore, remove it from key list if (getKeyAttributes().contains(attribute)) { if (!isAttributeKeyClassField(attribute.getName())) removeKeyAttribute(attribute,(String)oldValue); } // if renamed attribute is now part of the key, add it to the key list else attributeAdded(attribute); } /** * @param notification */ private void handlePrimKeyFieldEvent(Notification notification) { EObject newPrimKeyField = (EObject)notification.getNewValue(); cmp.setPrimKeyField((CMPAttribute)newPrimKeyField); // if primKeyField is removed or a proxy, recompute key attributes based on key class if (newPrimKeyField == null || newPrimKeyField.eIsProxy()) { CMPAttribute primField = (CMPAttribute)newPrimKeyField; if (primField!=null && primField.getName() == null) { primField.setName(((InternalEObject)primField).eProxyURI().toString()); makePrimKeyFieldProxy(primField.getName()); } removeAllKeyAttributes(); initialized = false; initializeKeyAttributes(); } // Ensure the key attributes list contains only the primKeyField attribute else if (!(getKeyAttributes().size()==1 && getKeyAttributes().contains(newPrimKeyField))) { primKeyFieldChanged(newPrimKeyField); } } /** * @param notification */ private void handleKeyClassEvent(Notification notification) { // if primkey null or proxy, clear key fields and reinitialize if key class not null if (cmp.getPrimKeyField()==null || cmp.getPrimKeyField().eIsProxy()) { keyClassChanged(); } // if primkey is not null, then do nothing } /** * @param notification */ private void handleCMPAttributeEvent(Notification notification) { int eventType = notification.getEventType(); // handle a CMPAttribute added if (eventType == Notification.ADD) { attributeAdded((CMPAttribute)notification.getNewValue()); } // handle a CMPAttribute removed else if (eventType == Notification.REMOVE) { CMPAttribute attribute = (CMPAttribute)notification.getOldValue(); // remove this adapter from the deleted attribute attribute.eAdapters().remove(this); removeKeyAttribute(attribute, attribute.getName()); } } protected void removeKeyAttribute(CMPAttribute attribute, String oldName) { // if attribute was a key attribute it will be removed, otherwise do nothing getKeyAttributes().remove(attribute); // if it is the prim key attribute, then make the prim key attribute a proxy if (cmp.getPrimKeyField()!=null && cmp.getPrimKeyField().equals(attribute)) { makePrimKeyFieldProxy(oldName); } } public void makePrimKeyFieldProxy(String oldName) { if (cmp.getPrimKeyField() == null) return; cmp.setPrimKeyField(EjbFactory.eINSTANCE.createCMPAttribute()); cmp.getPrimKeyField().setName(oldName); ((InternalEObject)cmp.getPrimKeyField()).eSetProxyURI(URI.createURI(oldName)); } protected void removeAllKeyAttributes() { // clear key attributes list on cmp getKeyAttributes().clear(); } protected void addKeyAttribute(CMPAttribute attribute) { CMPAttribute primKeyField = cmp.getPrimKeyField(); // if prim key is null add attribute to key list if (primKeyField==null || primKeyField.eIsProxy()) { if (!getKeyAttributes().contains(attribute)) getKeyAttributes().add(attribute); // if att is only key att, and type is the key class type, set the prim key field if (getKeyAttributes().size()==1 && attribute.getType().equals(cmp.getPrimaryKey())) cmp.setPrimKeyField(attribute); } // if primkey set + primkeyfield is the new attribute ensure its the only one else if (primKeyField.equals(attribute)) { if (!(getKeyAttributes().size()==1 && getKeyAttributes().contains(attribute))) { getKeyAttributes().clear(); getKeyAttributes().add(attribute); } } // if primkey set,new attribute not prim key, key atts > 1, remove primkey field else { cmp.setPrimKeyField(null); if (!getKeyAttributes().contains(attribute)) getKeyAttributes().add(attribute); } } protected void attributeAdded(CMPAttribute attribute) { //Make sure cmp key adapters are initialized if needed cmp.getKeyAttributes(); // add this as a listener to name changes on this attribute if (!attribute.eAdapters().contains(this)) attribute.eAdapters().add(this); if (attribute.getName() ==null) return; // add it to the key list if applicable and sort the key list if (isAttributeKeyClassField(attribute.getName())) { addKeyAttribute(attribute); sortKeyAttributeList(); } // if new attribute name is now prim key name, fix up prim key field else if (cmp.getPrimKeyField()!=null && cmp.getPrimKeyField().eIsProxy() && attribute.getName().equals(cmp.getPrimKeyField().getName())) { cmp.setPrimKeyField(attribute); primKeyFieldChanged(attribute); } } /** * Is the cmp attribute also a field in the key class? */ protected boolean isAttributeKeyClassField(String attributeName) { // ensure key class is not null JavaClass keyClass = cmp.getPrimaryKey(); if (keyClass == null) return false; // see if the attribute name matchs any of the reflected key class public field names List keyFields = keyClass.getFieldsExtended(); for (int i = 0; i < keyFields.size(); i++) { Field field = (Field) keyFields.get(i); if (field.getJavaVisibility() == JavaVisibilityKind.PUBLIC_LITERAL) { if (field.getName().equals(attributeName)) return true; } } return false; } /** * Sort the list of the key attributes to match the order of the key class */ private void sortKeyAttributeList() { List result = new ArrayList(); JavaClass keyClass = cmp.getPrimaryKey(); if (keyClass == null) return; List keyFields = keyClass.getFieldsExtended(); List currentKeys = getKeyAttributes(); // create a new list of the attributes in order of key class fields. for (int i = 0; i < keyFields.size(); i++) { Field field = (Field) keyFields.get(i); if (field.getJavaVisibility() == JavaVisibilityKind.PUBLIC_LITERAL) { //only public fields for (int j=0; j<currentKeys.size(); j++) { CMPAttribute attribute = (CMPAttribute) currentKeys.get(j); if (field.getName().equals(attribute.getName())) result.add(attribute); } } } //clear list and set the new key attribute order on the cmp getKeyAttributes().clear(); getKeyAttributes().addAll(result); } protected void keyClassChanged() { JavaClass key = cmp.getPrimaryKey(); if (key !=null) key.eAdapters().remove(this); // if not prim key class, clear key attribute list removeAllKeyAttributes(); initialized = false; initializeKeyAttributes(); } protected void primKeyFieldChanged(EObject primKeyField) { // if a primKeyField is added, do a remove all and an add removeAllKeyAttributes(); if (primKeyField != null && !primKeyField.eIsProxy()) { if (!primKeyField.eAdapters().contains(this)) primKeyField.eAdapters().add(this); getKeyAttributes().add(primKeyField); } } private EList getKeyAttributes() { return ((ContainerManagedEntityImpl)cmp).getKeyAttributesGen(); } /* (non-Javadoc) * @see org.eclipse.emf.common.notify.impl.AdapterImpl#setTarget(org.eclipse.emf.common.notify.Notifier) */ @Override public void setTarget(Notifier newTarget) { super.setTarget(newTarget); } /* (non-Javadoc) * @see org.eclipse.emf.common.notify.impl.AdapterImpl#isAdapterForType(java.lang.Object) */ @Override public boolean isAdapterForType(Object type) { return ADAPTER_TYPE.equals(type); } //To turn sync on or off public void setEnabled(boolean enabled){ isEnabled = enabled; } }