package org.ebayopensource.turmeric.eclipse.repositorysystem.ui.utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.ebayopensource.turmeric.eclipse.core.logging.SOALogger;
import org.ebayopensource.turmeric.eclipse.core.resources.constants.SOAProjectConstants;
import org.ebayopensource.turmeric.eclipse.exception.resources.SOAResourceModifyFailedException;
import org.ebayopensource.turmeric.eclipse.registry.ExtensionPointFactory;
import org.ebayopensource.turmeric.eclipse.registry.exception.ProviderException;
import org.ebayopensource.turmeric.eclipse.registry.intf.IClientRegistryProvider;
import org.ebayopensource.turmeric.eclipse.registry.intf.IRegistryProvider;
import org.ebayopensource.turmeric.eclipse.registry.models.ClientAssetModel;
import org.ebayopensource.turmeric.eclipse.registry.models.SubmitAssetModel;
import org.ebayopensource.turmeric.eclipse.repositorysystem.core.GlobalRepositorySystem;
import org.ebayopensource.turmeric.eclipse.repositorysystem.core.ISOAProjectConfigurer;
import org.ebayopensource.turmeric.eclipse.repositorysystem.core.TrackingEvent;
import org.ebayopensource.turmeric.eclipse.repositorysystem.resources.SOAMessages;
import org.ebayopensource.turmeric.eclipse.repositorysystem.utils.GlobalProjectHealthChecker;
import org.ebayopensource.turmeric.eclipse.repositorysystem.utils.TurmericServiceUtils;
import org.ebayopensource.turmeric.eclipse.resources.model.ISOAProject;
import org.ebayopensource.turmeric.eclipse.resources.model.SOAIntfMetadata;
import org.ebayopensource.turmeric.eclipse.resources.model.SOAIntfProject;
import org.ebayopensource.turmeric.eclipse.resources.util.SOAConsumerUtil;
import org.ebayopensource.turmeric.eclipse.resources.util.SOAIntfUtil;
import org.ebayopensource.turmeric.eclipse.resources.util.SOAServiceUtil;
import org.ebayopensource.turmeric.eclipse.utils.core.VersionUtil;
import org.ebayopensource.turmeric.eclipse.utils.plugin.EclipseMessageUtils;
import org.ebayopensource.turmeric.eclipse.utils.plugin.ProgressUtil;
import org.ebayopensource.turmeric.eclipse.utils.plugin.WorkspaceUtil;
import org.ebayopensource.turmeric.eclipse.utils.ui.UIUtil;
import org.ebayopensource.turmeric.eclipse.validator.utils.ValidateUtil;
import org.ebayopensource.turmeric.eclipse.validator.utils.common.AbstractBaseAccessValidator;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.progress.UIJob;
import org.osgi.framework.Version;
/**
* The Class ActionUtil.
*/
public class ActionUtil {
private static final SOALogger logger = SOALogger.getLogger();
/**
* Submit new client to soa registry.
*
* @param project the project
* @return the i status
* @throws Exception the exception
*/
public static IStatus submitNewClientToSOARegistry(IProject project)
throws Exception {
final IClientRegistryProvider regProvider = ExtensionPointFactory
.getSOAClientRegistryProvider();
if (regProvider == null) {
return EclipseMessageUtils.createStatus(
"Could not find a valid client registry provider",
IStatus.WARNING);
}
final ClientAssetModel clientModel = new ClientAssetModel();
final String clientName = SOAConsumerUtil.getClientName(project);
clientModel.setClientName(clientName);
final Properties props = SOAConsumerUtil
.loadConsumerProperties(project);
if (props.containsKey(SOAProjectConstants.PROPS_KEY_CONSUMER_ID)) {
final String consumerID = StringUtils.trim(props
.getProperty(SOAProjectConstants.PROPS_KEY_CONSUMER_ID));
clientModel.setConsumerId(consumerID);
}
// submit the model
return regProvider.submitNewClientAsset(clientModel);
}
/**
* submit new service from menu item. it will submit a service version to
* AR. This is the start of submit version to AR
*
* @param project the project
* @return the i status
*/
public static IStatus submitNewAssetToSOARegistry(IProject project) {
IRegistryProvider regProvider;
try {
regProvider = ExtensionPointFactory.getSOARegistryProvider();
if (regProvider == null)
throw new IllegalArgumentException(
"Could not find a valid SOA Registry Provider");
final SubmitAssetModel model = getAssetModel(project);
// submit the model
return regProvider.submitNewAssetForGovernance(model);
} catch (CoreException e) {
logger.error(e);
return EclipseMessageUtils.createErrorStatus(e);
} catch (ProviderException e) {
return handleExceptionFromAR(e);
} catch (Exception e) {
logger.error(e);
return EclipseMessageUtils.createErrorStatus(e);
}
}
/**
* Gets the asset model.
*
* @param project the project
* @return the asset model
* @throws Exception the exception
*/
public static SubmitAssetModel getAssetModel(IProject project)
throws Exception {
if (project == null
|| TurmericServiceUtils.isSOAInterfaceProject(project) == false) {
throw new IllegalArgumentException(
"Not a valid SOA interface project ->" + project);
}
// we trust the service name should be same as the project name
final String serviceName = project.getName();
// construct the model
final SubmitAssetModel model = new SubmitAssetModel();
String natureId = GlobalRepositorySystem.instanceOf().getActiveRepositorySystem()
.getTurmericProjectNatureId(project);
ISOAProject soaProject = SOAServiceUtil.loadSOAProject(project, natureId);
SOAIntfMetadata metadata = (SOAIntfMetadata) soaProject.getMetadata();
if (StringUtils.isNotBlank(metadata.getPublicServiceName())) {
// post 2.4 services
model.setServiceName(metadata.getPublicServiceName());
model.setAdminName(metadata.getServiceName());
} else {
// pre 2.4 services, adminName=serviceName
model.setServiceName(metadata.getServiceName());
model.setAdminName(metadata.getServiceName());
}
model.setNamespacePart(metadata.getServiceNamespacePart());
model.setInterfaceProjectPath(project.getLocation().toString());
model.setServiceLayer(metadata.getServiceLayer());
model.setServiceNamespace(metadata.getTargetNamespace());
model.setServiceVersion(metadata.getServiceVersion());
model.setServiceWsdlLocation(SOAServiceUtil.getWsdlFile(project,
serviceName).getLocation().toString());
if (StringUtils.isBlank(metadata.getServiceDomainName())) {
logger
.warning(
"Service domain name is missing. Please check service_intf_project.properties of the project and make sure 'domainName' propery is set.",
"\n\nIf the service is created before installing AR plugin, then please either re-create the service or manually add 'domainName={DomainName}' to service_intf_project.properties and substitute the {DomainName}.");
}
model.setServiceDomain(metadata.getServiceDomainName());
return model;
}
/**
* Update existing asset version to soa registry.
*
* @param project the project
* @return the i status
*/
public static IStatus updateExistingAssetVersionToSOARegistry(
IProject project) {
IRegistryProvider regProvider;
try {
regProvider = ExtensionPointFactory.getSOARegistryProvider();
if (regProvider == null)
throw new IllegalArgumentException(
"Could not find a valid SOA Registry Provider");
final SubmitAssetModel model = getAssetModel(project);
// submit the model
return regProvider.updateExistingVersionForGovernance(model);
} catch (CoreException e) {
logger.error(e);
return EclipseMessageUtils.createErrorStatus(e);
} catch (ProviderException e) {
return handleExceptionFromAR(e);
} catch (Exception e) {
logger.error(e);
return EclipseMessageUtils.createErrorStatus(e);
}
}
/**
* submit a new minor version to AR.
*
* @param project the project
* @param newVersion the new version
* @return the i status
*/
public static IStatus submitNewVersionAssetToSOARegistry(IProject project,
String newVersion) {
IRegistryProvider regProvider;
try {
regProvider = ExtensionPointFactory.getSOARegistryProvider();
if (regProvider == null) {
return EclipseMessageUtils.createStatus(
SOAMessages.WARNING_AR_NOT_AVAILABLE, IStatus.WARNING);
}
final SubmitAssetModel model = getAssetModel(project);
if (newVersion != null && newVersion.trim().length() > 0) {
model.setServiceVersion(newVersion);
}
// submit the model
return regProvider.submitNewVersionForGovernance(model);
} catch (CoreException e) {
logger.error(e);
return EclipseMessageUtils.createErrorStatus(e);
} catch (ProviderException e) {
return handleExceptionFromAR(e);
} catch (Exception e) {
logger.error(e);
return EclipseMessageUtils.createErrorStatus(e);
}
}
/**
* when exception thrown from AR, it is not friendly. This method gets the
* root cause of the exception and create an error status for the exception,
* using a description
* SOAMessages.ERROR_FAIL_TO_SUBMIT_SERVICE_VERSION_TO_AR
*
* @param e
* @return
*/
private static IStatus handleExceptionFromAR(Throwable e) {
logger.error(e);
Throwable rootCause = e.getCause();
if (rootCause == null) {
return EclipseMessageUtils.createErrorStatus(e);
} else {
while (rootCause.getCause() != null) {
rootCause = rootCause.getCause();
}
if (rootCause instanceof LinkageError) {
logger.error(rootCause);
return EclipseMessageUtils.createErrorStatus(
SOAMessages.ERROR_AR_OUT_OF_DATE, null);
} else {
return EclipseMessageUtils.createErrorStatus(
SOAMessages.ERROR_FAIL_TO_SUBMIT_SERVICE_VERSION_TO_AR,
rootCause);
}
}
}
/**
* Submite a service maintenance version. For Backward Compatibility, using
* reflect to call new added method. Show error message if method not found
* and notify users to update to latest version.
*
* @param project the project
* @param newVersion the new version
* @return the i status
* @throws Exception the exception
*/
public static IStatus submitServiceMaintenanceVersion(IProject project,
String newVersion) throws Exception {
final IRegistryProvider regProvider = ExtensionPointFactory
.getSOARegistryProvider();
if (regProvider == null) {
return EclipseMessageUtils.createStatus(
SOAMessages.WARNING_AR_NOT_AVAILABLE, IStatus.WARNING);
}
// use reflect for backward compatible.
try {
Method submitNewMaintenanceVersionMethod = regProvider.getClass()
.getMethod("submitNewMaintenanceVersion",
SubmitAssetModel.class);
SubmitAssetModel model = getAssetModel(project);
if (newVersion != null && newVersion.trim().length() > 0) {
model.setServiceVersion(newVersion);
}
Object retStatus = submitNewMaintenanceVersionMethod.invoke(
regProvider, model);
return (IStatus) retStatus;
} catch (NoSuchMethodException ex) {
logger.error(ex);
return EclipseMessageUtils.createErrorStatus(
SOAMessages.ERROR_AR_OUT_OF_DATE, null);
} catch (SecurityException ex) {
return EclipseMessageUtils.createErrorStatus(ex);
} catch (InvocationTargetException ex) {
return handleExceptionFromAR(ex);
}
}
/**
* Submit version to asset repository.
*
* @param newVersion the new version
* @param oldVersion the old version
* @param svcIntfName the svc intf name
* @param monitor the monitor
* @return the i status
* @throws Exception the exception
*/
public static IStatus submitVersionToAssetRepository(Object newVersion,
Object oldVersion, String svcIntfName, IProgressMonitor monitor)
throws Exception {
Version newVer = VersionUtil.getVersion(newVersion);
Version oldVer = VersionUtil.getVersion(oldVersion);
monitor.setTaskName("Synchronize service version with "
+ "Asset Repository for project->" + svcIntfName
+ ", from version [" + oldVer + "], to version [" + newVer
+ "].");
// no version format check here because it is checked when version
// changed.
// here we use not equal but not bigger than to decide if a version is
// changed.
// Only show when service version is changed this time.
boolean miniorChanged = newVer.getMinor() != oldVer.getMinor();
boolean mantanChanged = newVer.getMicro() != oldVer.getMicro();
final boolean syncVersion;
if (miniorChanged || mantanChanged) {
syncVersion = UIUtil
.openChoiceDialog(
"Synchronize Service Version",
"Service version has been updated to ["
+ newVer
+ "] in local metadata. "
+ "Would you like to synchronize service version change to the Asset Repository?",
MessageDialog.QUESTION_WITH_CANCEL);
} else {
logger.info("Service Version not changed:" + newVer
+ ". Exist submitVersionToAssetRepository");
return Status.CANCEL_STATUS;
}
if (syncVersion == false) {
return Status.CANCEL_STATUS;
}
try {
IStatus result = null;
IProject intfProj = WorkspaceUtil.getProject(svcIntfName);
if (miniorChanged == true) {
result = ActionUtil.submitNewVersionAssetToSOARegistry(
intfProj, newVer.toString());
} else if (mantanChanged == true) {
result = ActionUtil.submitServiceMaintenanceVersion(intfProj,
newVer.toString());
} else {
logger.info("Service Version not changed:" + newVer
+ ". Exist submitVersionToAssitionRepository");
}
if (result != null) {
if (result.isOK() == true) {
GlobalRepositorySystem.instanceOf()
.getActiveRepositorySystem().trackingUsage(
new TrackingEvent(ActionUtil.class
.getName(),
TrackingEvent.TRACKING_ACTION));
} else {
UIUtil
.showErrorDialog(
(Shell) null,
"Service Version Synchronize Failed",
"Failed to synchronize service version with Asset Repository.",
result);
}
}
} catch (Exception e) {
logger.error(e);
throw new SOAResourceModifyFailedException(
"Failed to synchronize service version for project->"
+ svcIntfName + ", from version [" + oldVer
+ "] to version [" + newVer + "].", e);
} finally {
monitor.done();
}
return null;
}
/**
* this is used to update interface project version. It combines the
* following operations: 1) Update local metadata 2) sync version with AR if
* AR is available. Notify users before doing it. It is cancelable. 3) do a
* v3 build if it is v3 mode. Notify users before doing it. Library Catalog
* version need to be synchronized before doing a v3 build. It is
* cancelable.
*
* This method will be used in service property page when changing service
* version. And also be used in V3 when calling a Build Service in right
* click menu.
*
* This method is meant to be invoked in the UI thread.
*
* @param soaIntfProject the interface project that need to be updated
* @param oldVersion service old version
* @param newVersion service new version.
* @param silence just for the repos that need build after version change.
* @param monitor the progress monitor
* @throws Exception the exception
*/
public static void updateInterfaceProjectVersion(final SOAIntfProject soaIntfProject,
String oldVersion, String newVersion, boolean silence, IProgressMonitor monitor) throws Exception{
ISOAProjectConfigurer configurer = GlobalRepositorySystem.instanceOf()
.getActiveRepositorySystem().getProjectConfigurer();
ProgressUtil.progressOneStep(monitor);
if (StringUtils.equals(oldVersion, newVersion) == true) {
logger.info("Service version not change : " + newVersion);
// still need try to build service if version not changed.
if (silence == true) {
configurer.postServiceVersionUpdated(soaIntfProject,
oldVersion, newVersion, silence, monitor);
}
return;
}
final IProject intfProject= soaIntfProject.getProject();
final String serviceName = intfProject.getName();
final IStatus status = new AbstractBaseAccessValidator() {
@Override
public List<IResource> getReadableFiles() {
//should check the following files
try {
return GlobalProjectHealthChecker.getSOAProjectReadableResources(intfProject);
} catch (Exception e) {
logger.warning(e);
}
return new ArrayList<IResource>(1);
}
@Override
public List<IResource> getWritableFiles() {
final List<IResource> files = new ArrayList<IResource>();
files.add(SOAIntfUtil.getMetadataFile(intfProject, serviceName));
files.add(SOAServiceUtil.getWsdlFile(intfProject, serviceName));
return files;
}
}.validate(serviceName);
final String messages = ValidateUtil.getFormattedStatusMessagesForAction(status);
if (messages != null) {
UIUtil.showErrorDialog(UIUtil.getActiveShell(), "Error",
messages, (Throwable)null);
return;
}
soaIntfProject.getMetadata().setServiceVersion(newVersion);
// update local meta data.
ProgressUtil.progressOneStep(monitor);
configurer.updateProject(soaIntfProject, false, monitor);
ProgressUtil.progressOneStep(monitor);
// synchronize with AR if available.
// although submitVersionToAssitionRepository will check
// version change or not. here we add a check to avoid
// creating a UIJob.
if (GlobalRepositorySystem.instanceOf()
.getActiveRepositorySystem()
.getActiveOrganizationProvider()
.supportAssetRepositoryIntegration() == true
&& ExtensionPointFactory
.getSOARegistryProvider() != null) {
final Version newVer = new Version(newVersion);
final Version oldVer = new Version(oldVersion);
ProgressUtil.progressOneStep(monitor);
// no version check here because it is checked when
// version changed.
UIJob updateVersion = new UIJob(
"Synchornizing service version with Asset Repository.") {
@Override
public IStatus runInUIThread(
IProgressMonitor monitor) {
try {
ActionUtil
.submitVersionToAssetRepository(
newVer, oldVer,
soaIntfProject.getProjectName(), monitor);
} catch (Exception e) {
logger.error(e);
}
return Status.OK_STATUS;
}
};
updateVersion.schedule();
}
ProgressUtil.progressOneStep(monitor);
// trigger build is needed.
configurer.postServiceVersionUpdated(soaIntfProject,
oldVersion, newVersion, silence, monitor);
}
}