| /******************************************************************************* |
| * Copyright (c) 2003, 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 |
| *******************************************************************************/ |
| package org.eclipse.jst.j2ee.internal.common; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.emf.common.notify.AdapterFactory; |
| 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.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.jem.internal.adapters.jdom.JavaJDOMAdapterFactory; |
| import org.eclipse.jem.internal.java.adapters.ReadAdaptor; |
| import org.eclipse.jem.internal.java.adapters.ReflectionAdaptor; |
| import org.eclipse.jem.java.Field; |
| import org.eclipse.jem.java.JavaClass; |
| import org.eclipse.jem.java.JavaVisibilityKind; |
| import org.eclipse.jem.java.util.NotificationUtil; |
| import org.eclipse.jem.util.emf.workbench.ProjectUtilities; |
| import org.eclipse.jem.util.emf.workbench.nature.EMFNature; |
| import org.eclipse.jst.j2ee.ejb.CMPAttribute; |
| import org.eclipse.jst.j2ee.ejb.ContainerManagedEntity; |
| import org.eclipse.jst.j2ee.ejb.EJBJar; |
| import org.eclipse.jst.j2ee.ejb.EjbPackage; |
| import org.eclipse.jst.j2ee.ejb.internal.impl.EjbFactoryImpl; |
| |
| /** |
| * This adapter is used to listen for changes to the ejb class or the primary key class in order to |
| * reflect the proper CMP field types and the proper key attributes. |
| */ |
| public class CMPJavaChangeSynchronizationAdapter extends AdapterImpl { |
| |
| private static final String J2EE_PROJ_MIGRATION_ADAPTER = "J2EEProjectMigration"; //$NON-NLS-1$ |
| |
| protected static EjbPackage EJB_PACK = EjbFactoryImpl.getPackage(); |
| |
| private static HashMap enablementMap = new HashMap(); |
| |
| public static void disable(ContainerManagedEntity cmp) { |
| enablementMap.put(cmp, Boolean.FALSE); |
| } |
| |
| public static void enable(ContainerManagedEntity cmp) { |
| enablementMap.put(cmp, Boolean.TRUE); |
| } |
| |
| public static boolean isEnabled(ContainerManagedEntity cmp) { |
| if (!enablementMap.containsKey(cmp)) |
| return true; |
| return ((Boolean) enablementMap.get(cmp)).booleanValue(); |
| } |
| |
| protected Resource cmpResource; |
| |
| private List foundKeys = new ArrayList(); |
| |
| /* |
| * This Set is used to avoid reacting to notifications for a notifier while |
| * updating that notifier. |
| */ |
| private Set updatingSet = new HashSet(); |
| |
| public CMPJavaChangeSynchronizationAdapter() { |
| super(); |
| } // EJBKeyShapeMaintenanceAdapter |
| |
| /** |
| * Notifies if there is change in the key shape. |
| * |
| * @param Notification |
| * msg - Message indicates what has changed. |
| */ |
| @Override |
| public void notifyChanged(Notification msg) { |
| if (!isEnabled(getCMP())) { |
| enable(getCMP()); |
| return; |
| } |
| Object notifier = msg.getNotifier(); |
| if (!updatingSet.contains(notifier)) { |
| try { |
| updatingSet.add(notifier); |
| switch (msg.getEventType()) { |
| case Notification.SET : |
| setNotification(msg); |
| break; |
| case Notification.UNSET : |
| unsetNotification(msg); |
| break; |
| case Notification.REMOVING_ADAPTER : |
| removeAdapterNotification(msg); |
| break; |
| case ReflectionAdaptor.EVENT : |
| jemFlushNotification(msg); |
| break; |
| } |
| } finally { |
| updatingSet.remove(notifier); |
| } |
| } |
| } |
| |
| /** |
| * Use if the there was an set notification. |
| * |
| * @param Notification |
| * msg - Message indicates what has changed. |
| */ |
| protected void setNotification(Notification msg) { |
| EStructuralFeature sf = (EStructuralFeature) msg.getFeature(); |
| if (sf == EJB_PACK.getEnterpriseBean_EjbClass() || sf == EJB_PACK.getEntity_PrimaryKey()) { |
| if (!isMigrating()) { |
| removeAttributeMaintenanceAdapter((Notifier) msg.getOldValue()); |
| addAttributeMaintenanceAdapter((Notifier) msg.getNewValue()); |
| touchKeyShapeAdapter(msg); |
| } |
| } else if (sf == EJB_PACK.getEntity_PrimaryKey()) { |
| removeAttributeMaintenanceAdapter((Notifier) msg.getOldValue()); |
| if (shouldAddToPrimaryKeyClass((ContainerManagedEntity) getTarget())) |
| addAttributeMaintenanceAdapter((Notifier) msg.getNewValue()); |
| } else { |
| jemFlushNotification(msg); //In EMF a TOUCH is a SET. |
| } |
| } // setNotification |
| |
| /** |
| * @return |
| */ |
| private boolean isMigrating() { |
| EJBJar jar = ((ContainerManagedEntity) getTarget()).getEjbJar(); |
| if (jar != null) |
| return EcoreUtil.getExistingAdapter(jar, J2EE_PROJ_MIGRATION_ADAPTER) != null; |
| return false; |
| } |
| |
| // setNotification |
| /** |
| * Use if the there was an unset notification. |
| * |
| * @param Notification |
| * msg - Message indicates what has changed. |
| */ |
| protected void unsetNotification(Notification msg) { |
| EStructuralFeature sf = (EStructuralFeature) msg.getFeature(); |
| if ((sf == EJB_PACK.getEnterpriseBean_EjbClass() || sf == EJB_PACK.getEntity_PrimaryKey()) && !isMigrating()) { |
| removeAttributeMaintenanceAdapter((Notifier) msg.getOldValue()); |
| } |
| } // unsetNotification |
| |
| /** |
| * Use if the there was an touch notification. |
| * |
| * @param Notification |
| * msg - Message indicates what has changed. |
| */ |
| protected void jemFlushNotification(Notification msg) { |
| if ((NotificationUtil.isFlushNewEvent(msg) || NotificationUtil.isFlushEvent(msg)) && !isMigrating()) { |
| if (msg.getNotifier() == ((ContainerManagedEntity) getTarget()).getEjbClass()) { |
| touchBeanAdapter(msg); |
| } else if (msg.getNotifier() == ((ContainerManagedEntity) getTarget()).getPrimaryKey()) { |
| touchKeyShapeAdapter(msg); |
| } // if |
| //if the notifier is eq the primary key |
| //else ejb bean class flush |
| } // if |
| } // touchNotification |
| |
| protected void removeAdapterNotification(Notification msg) { |
| if (msg.getOldValue() == this && msg.getNotifier() instanceof ContainerManagedEntity) { |
| ContainerManagedEntity cmp = (ContainerManagedEntity) msg.getNotifier(); |
| if (cmp.getEjbClass() != null) |
| cmp.getEjbClass().eAdapters().remove(this); |
| if (cmp.getPrimaryKey() != null) |
| cmp.getPrimaryKey().eAdapters().remove(this); |
| } |
| } |
| |
| /** |
| * Adds the key shape adapter |
| * |
| * @param Notifier |
| * notifier - The current notifier. |
| */ |
| protected void addAttributeMaintenanceAdapter(Notifier notifier) { |
| if (notifier != null && !notifier.eAdapters().contains(this)) |
| notifier.eAdapters().add(this); |
| } |
| |
| /** |
| * Remove the key shape adapter |
| */ |
| protected void removeAttributeMaintenanceAdapter(Notifier notifier) { |
| if (notifier != null) |
| notifier.eAdapters().remove(this); |
| } |
| |
| /** |
| * The key has been touched. |
| * |
| * @param Notification |
| * msg - The notification message. |
| */ |
| protected void touchKeyShapeAdapter(Notification msg) { |
| if (msg == null) |
| return; |
| ContainerManagedEntity cmp = (ContainerManagedEntity) getTarget(); |
| JavaClass primaryKeyClass = cmp.getPrimaryKey(); |
| //Synch the two lists. |
| synchCMPandKeyAttributes(cmp, primaryKeyClass); |
| } // touchKeyShapeAdapter |
| |
| /** |
| * The ejb class has been flushed. |
| * |
| * @param Notification |
| * msg - The notification message. |
| */ |
| protected void touchBeanAdapter(Notification msg) { |
| if (msg == null) |
| return; |
| ContainerManagedEntity cmp = (ContainerManagedEntity) getTarget(); |
| List cmpAttributes = cmp.getPersistentAttributes(); |
| if (cmpAttributes != null && !cmpAttributes.isEmpty()) { |
| boolean modFlag = getCurrentModificationFlag(); |
| try { |
| for (int i = 0; i < cmpAttributes.size(); i++) { |
| CMPAttribute cmpAttr = (CMPAttribute) cmpAttributes.get(i); |
| if (cmpAttr != null && !cmpAttr.isDerived()) { |
| cmpAttr.setEType(null); |
| } |
| } |
| } finally { |
| setModificationFlag(modFlag); |
| } |
| } |
| synchCMPandKeyAttributes(cmp, cmp.getPrimaryKey()); |
| } |
| |
| /** |
| * Synchronzies the cmp and primary key class attributes. |
| * |
| * @param ContainerManagedEntity |
| * cmp - The cmp. |
| * @param JavaClass |
| * primaryKeyClass |
| */ |
| protected void synchCMPandKeyAttributes(ContainerManagedEntity cmp, JavaClass primaryKeyClass) { |
| if (cmp == null || primaryKeyClass == null || cmp.getPrimKeyField() != null || primaryKeyClass.getQualifiedName().startsWith("java.lang")) //$NON-NLS-1$ |
| return; |
| |
| // make sure we flush the primary key to get latest updates if no save |
| // took place |
| flushPrimaryKeyClass(primaryKeyClass); |
| |
| List cmpAttributes = cmp.getPersistentAttributes(); |
| if (cmpAttributes != null) { |
| foundKeys.clear(); |
| List keyAttributesList = cmp.getKeyAttributes(); |
| foundKeys.addAll(keyAttributesList); |
| boolean modFlag = getCurrentModificationFlag(); |
| try { |
| List keyFields = primaryKeyClass.getFieldsExtended(); |
| for (int i = 0; i < keyFields.size(); i++) { |
| Field field = (Field) keyFields.get(i); |
| if (field.getJavaVisibility() != JavaVisibilityKind.PUBLIC_LITERAL) |
| continue; |
| String fieldName = field.getName(); |
| if (fieldName != null) { |
| CMPAttribute keyAttr = cmp.getKeyAttribute(fieldName); |
| if (keyAttr == null) |
| cmp.addKeyAttributeName(fieldName); |
| else |
| foundKeys.remove(keyAttr); |
| } |
| } |
| if (!foundKeys.isEmpty()) |
| keyAttributesList.removeAll(foundKeys); |
| } finally { |
| setModificationFlag(modFlag); |
| } |
| } |
| } |
| |
| @Override |
| public void setTarget(Notifier newTarget) { |
| boolean isChanged = getTarget() != newTarget; |
| if (newTarget == null) { |
| super.setTarget(newTarget); |
| cmpResource = null; |
| } else if (newTarget instanceof ContainerManagedEntity) { |
| Resource res = ((ContainerManagedEntity) newTarget).eResource(); |
| if (res != null && res.getResourceSet() != null) { |
| super.setTarget(newTarget); |
| if (isChanged) |
| initializeTarget(); |
| } |
| } |
| } |
| |
| /** |
| * |
| */ |
| private void initializeTarget() { |
| ContainerManagedEntity cmp = (ContainerManagedEntity) getTarget(); |
| addAttributeMaintenanceAdapter(cmp.getEjbClass()); |
| if (shouldAddToPrimaryKeyClass(cmp)) |
| addAttributeMaintenanceAdapter(cmp.getPrimaryKey()); |
| } |
| |
| private boolean shouldAddToPrimaryKeyClass(ContainerManagedEntity cmp) { |
| return cmp.getPrimKeyField() == null && cmp.getPrimaryKey() != null && !cmp.getPrimaryKey().getQualifiedName().startsWith("java.lang"); //$NON-NLS-1$ |
| } |
| |
| protected Resource getCMPResource() { |
| if (cmpResource == null && getTarget() != null) |
| cmpResource = ((EObject) getTarget()).eResource(); |
| return cmpResource; |
| } |
| |
| protected boolean getCurrentModificationFlag() { |
| return getCMPResource() != null && cmpResource.getContents() != null ? cmpResource.isModified() : false; |
| } |
| |
| protected void setModificationFlag(boolean aBoolean) { |
| if (getCMPResource() != null) |
| getCMPResource().setModified(aBoolean); |
| } |
| |
| public ContainerManagedEntity getCMP() { |
| if (getTarget() instanceof ContainerManagedEntity) |
| return (ContainerManagedEntity) getTarget(); |
| return null; |
| } |
| |
| protected boolean flushPrimaryKeyClass(JavaClass primaryKeyClass) { |
| // ensure the primary key class is flushed and reloaded to get latest |
| // content |
| IProject p = ProjectUtilities.getProject(primaryKeyClass); |
| try { |
| List natures = EMFNature.getRegisteredRuntimes(p); |
| EMFNature nature = null; |
| for (int i = 0; i < natures.size(); i++) { |
| if (natures.get(i) instanceof EMFNature) |
| nature = (EMFNature) natures.get(i); |
| } |
| if(nature !=null ){ |
| List adapterFactories = nature.getResourceSet().getAdapterFactories(); |
| AdapterFactory factory = EcoreUtil.getAdapterFactory(adapterFactories, ReadAdaptor.TYPE_KEY); |
| if (factory instanceof JavaJDOMAdapterFactory) { |
| JavaJDOMAdapterFactory javaFactory = (JavaJDOMAdapterFactory) factory; |
| javaFactory.flushReflectionNoNotification(primaryKeyClass.getQualifiedName()); |
| return true; |
| } |
| } |
| } catch (Exception e) { |
| // We don't really care what the exception was, we'll just bail out |
| // and return false; |
| } |
| return false; |
| } |
| } |