blob: 9df25364c7407db105248b897c425735b290a2eb [file] [log] [blame]
/*******************************************************************************
* 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;
}
}