blob: 1496b1cf1f1c3bcd653b16606be8fc23484eee83 [file] [log] [blame]
/***********************************************************************
* Copyright (c) 2008 by SAP AG, Walldorf.
* 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:
* SAP AG - initial API and implementation
***********************************************************************/
package org.eclipse.jst.jee.model.internal;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jst.j2ee.model.IModelProvider;
import org.eclipse.jst.j2ee.model.IModelProviderEvent;
import org.eclipse.jst.j2ee.model.IModelProviderListener;
import org.eclipse.jst.javaee.ejb.EJBJar;
import org.eclipse.jst.javaee.ejb.EjbFactory;
import org.eclipse.jst.jee.model.internal.common.AbstractMergedModelProvider;
import org.eclipse.jst.jee.model.internal.mergers.EjbJarMerger;
import org.eclipse.jst.jee.model.internal.mergers.ModelElementMerger;
import org.eclipse.jst.jee.model.internal.mergers.ModelException;
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
/**
* This model provider gives a "merged" view of the model loaded from the
* deployment descriptor and from annotated java classes.
*
* <p>
* A "merged" view contains all the elements that are described in the xml but
* not with annotation.
*
* A "merged" view contains all the elements that are described with annotations
* but not in the xml.
*
* In case of conflicts a "merged" view contains the value of the xml.
* </p>
*
*
* Listeners registered with {@link #addListener(IModelProviderListener)} will
* receive notification for changes in the deployment descriptor and in the
* annotations model. Notifications may come in different thread from the one
* changing the resource.
*
* <p>
* After a notification for changes in the model it is mandatory to call
* {@link #getModelObject()} to get a new reference to the model object. A new
* model object might have been created after processing the notification and
* merging the views.
* </p>
*
* In case there is an ejb-client-jar element in the deployment descriptor
* EJB3MergedModelProvider will provide this information to the
* {@link EJBAnnotationReader}.
*
*
*
* @author Kiril Mitov k.mitov@sap.com
*
*/
public class EJB3MergedModelProvider extends AbstractMergedModelProvider<EJBJar> {
private IProject clientProject;
public EJB3MergedModelProvider(IProject project) {
super(project);
}
@Override
protected IModelProvider loadAnnotationModel(EJBJar ddModel) throws CoreException {
if (ddModel.getEjbClientJar() != null)
clientProject = ResourcesPlugin.getWorkspace().getRoot().getProject(
getClientNameFromJarName(ddModel.getEjbClientJar()));
return new EJBAnnotationReader(ProjectFacetsManager.create(project), clientProject);
}
@Override
protected IModelProvider loadDeploymentDescriptorModel() throws CoreException {
return new Ejb3ModelProvider(project);
}
protected EJBJar getAnnotationEjbJar() {
return (EJBJar) annotationModelProvider.getModelObject();
}
protected EJBJar getXmlEjbJar() {
return (EJBJar) ddProvider.getModelObject();
}
public Object getModelObject(IPath modelPath) {
return null;
}
public void modify(Runnable runnable, IPath modelPath) {
/*
* Someone has called modify before loading the model. Try to load the
* model.
*/
if (mergedModel == null)
getMergedModel();
if (isDisposed()) {
return;
}
modifyWithBackup(runnable, modelPath);
}
/*
* The method will call modify to the ddProvider and during this time the
* getMergedModel() method will return the ddModel.
*
* After dd modify is finished there will be a merge between dd model and
* annotation model.
*
* During dd modify there might be notifications from ddProvider which will
* result in changes of the mergedModel.
*/
private void modifyWithBackup(Runnable runnable, IPath modelPath) {
EJBJar backup = mergedModel;
try {
mergedModel = (EJBJar) ddProvider.getModelObject();
ddProvider.modify(runnable, modelPath);
} finally {
mergedModel = backup;
}
clearModel(mergedModel);
/*
* Reload the model.
*/
merge(getXmlEjbJar(), getAnnotationEjbJar());
}
protected void annotationModelChanged(IModelProviderEvent event) {
internalModelChanged(event);
}
protected void xmlModelChanged(IModelProviderEvent event) {
internalModelChanged(event);
}
/*
* Notifications from xml and annotation may come in different threads. This
* depends on the implementation of the model providers, but to make sure
* that no race conditions occurs I am synchronizing this method.
*/
private synchronized void internalModelChanged(IModelProviderEvent event) {
/*
* The client project was changed. Reload the annotation model.
*/
if (clientProject == null && getXmlEjbJar().getEjbClientJar() != null) {
reloadAnnotationModel();
} else if (clientProject != null
&& !clientProject.getName().equals(getClientNameFromJarName(getXmlEjbJar().getEjbClientJar()))) {
reloadAnnotationModel();
}
merge(getXmlEjbJar(), getAnnotationEjbJar());
notifyListeners(event);
}
private void reloadAnnotationModel() {
try {
disableInternalNotifications();
((EJBAnnotationReader) annotationModelProvider).dispose();
annotationModelProvider = loadAnnotationModel(getXmlEjbJar());
enableInternalNotifications();
} catch (CoreException e) {
e.printStackTrace();
}
}
private String getClientNameFromJarName(String jarName) {
if (jarName == null)
return null;
if (jarName.endsWith(".jar")) //$NON-NLS-1$
return jarName.substring(0, jarName.lastIndexOf(".jar")); //$NON-NLS-1$
return jarName;
}
@Override
protected EJBJar merge(EJBJar ddModel, EJBJar annotationsModel) {
try {
if (mergedModel == ddModel) {
mergeWithModel(annotationsModel);
} else {
clearModel(mergedModel);
mergedModel.setEnterpriseBeans(EjbFactory.eINSTANCE.createEnterpriseBeans());
mergeWithModel(ddModel);
mergeWithModel(annotationsModel);
}
} catch (ModelException e) {
e.printStackTrace();
}
return mergedModel;
}
private void mergeWithModel(EJBJar annotationsModel) throws ModelException {
EjbJarMerger merger = new EjbJarMerger(mergedModel, annotationsModel, ModelElementMerger.ADD);
merger.process();
}
private void clearModel(EJBJar jar) {
jar.setAssemblyDescriptor(null);
jar.setEnterpriseBeans(null);
jar.getDescriptions().clear();
jar.getDisplayNames().clear();
jar.setRelationships(null);
jar.setEjbClientJar(null);
jar.setInterceptors(null);
jar.getIcons().clear();
}
@Override
protected EJBJar createNewModelInstance() {
return EjbFactory.eINSTANCE.createEJBJar();
}
}