/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.advisor.ui.views.status;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventObject;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.swt.widgets.Display;
import org.teiid.core.designer.event.EventObjectListener;
import org.teiid.core.designer.event.EventSourceException;
import org.teiid.core.designer.event.IChangeListener;
import org.teiid.core.designer.event.IChangeNotifier;
import org.teiid.designer.advisor.ui.AdvisorUiConstants;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.ui.UiPlugin;
import org.teiid.designer.ui.common.viewsupport.JobUtils;
import org.teiid.designer.ui.event.ModelResourceEvent;
/**
*
*/
public class AdvisorStatusManager implements IChangeListener {
private static StatusValidationHelper helper;
public static final Object FAMILY_MODEL_PROJECT_STATUS = new Object();
private static final String JOB_NAME = "Data Services Project Advisor Validation"; //$NON-NLS-1$
private static final String AUTOBUILD_JOB_NAME = "Building workspace"; //$NON-NLS-1$
private Collection statusListeners;
private EventObjectListener modelResourceListener;
private IResourceChangeListener resourceListener;
private ModelProjectStatus currentStatus;
StatusUpdateJob statusRefreshJob;
private AutoBuildJobListener autoBuildJobListener;
boolean isListeningForBuildComplete = false;
private IProject currentProject;
private static boolean enabled;
/**
* @since 4.3
*/
public AdvisorStatusManager() {
super();
init();
enabled = true;
}
private void init() {
AdvisorStatusManager.helper = new StatusValidationHelper();
this.statusListeners = new ArrayList();
this.autoBuildJobListener = new AutoBuildJobListener();
// viewWorker = VdbViewUtil.getVdbViewWorker();
this.statusRefreshJob = new StatusUpdateJob(JOB_NAME);
// Connect to VdbView
registerAsListener();
// System.out.println(" WebServicesValidationManager.init() calling updateStatus()");
updateStatus(false);
}
public void updateStatus( boolean forceUpdate ) {
// First check if the workbench state is OK and that there are listeners who care...
// IF NOT, then RETURN and DO NOTHING
if (!shouldNotify()) {
return;
}
// if (!registeredWithVdbViewWorker) {
// registerWithVdbViewWorker();
// }
if (JobUtils.validationJobsExist()) {
if (!isListeningForBuildComplete) {
if (ModelerCore.getWorkspace().isAutoBuilding()) {
// System.out.println(" WSVM.updateStatus(): ##### validation running #####. AUTOBUILD = " +
// ModelerCore.getWorkspace().isAutoBuilding());
Platform.getJobManager().addJobChangeListener(this.autoBuildJobListener);
isListeningForBuildComplete = true;
} else {
isListeningForBuildComplete = false;
}
}
return;
}
// Update the status
boolean workspaceChanged = false;
boolean forceJob = false;
// if (viewWorker.getCurrentVdbContext() != null && currentVdbContext != null) {
// if (viewWorker.getCurrentVdbContext() == currentVdbContext) {
// contextChanged = false;
// } else {
// contextChanged = true;
// setCurrentVdbContext(viewWorker.getCurrentVdbContext());
// }
// } else if (viewWorker.getCurrentVdbContext() == null && currentVdbContext != null) {
// contextChanged = true;
// setCurrentVdbContext(viewWorker.getCurrentVdbContext());
// } else if (viewWorker.getCurrentVdbContext() != null && currentVdbContext == null) {
// contextChanged = true;
// setCurrentVdbContext(viewWorker.getCurrentVdbContext());
// }
//
// if (contextChanged) {
// // Job[] wsJobs = Platform.getJobManager().find(FAMILY_WEB_SERVICE_STATUS);
// // int nJobs = wsJobs.length;
// // System.out.println(" ====>> WSVM.updateStatus(): Context Changed, Cancel all UPDATE JOBS. N Jobs = " + nJobs);
// Platform.getJobManager().cancel(FAMILY_WEB_SERVICE_STATUS);
// }
// statusRefreshJob.setContextChanged(contextChanged);
//
// // If the context changed, we want to reset the context on the helper, then force
// // a job to be queued, maybe cancel any that are pending.
// if (contextChanged) {
// forceJob = true;
// }
if (forceJob || shouldAddJob() || forceUpdate) {
// On startup, the Default display thread may not be available, so ....
if (Display.getDefault() == null) {
// System.out.println(" WSVM.updateStatus() No Default Thread, so update without it");
ModelProjectStatus status = generateNewStatus();
if (status != null) {
status.setWorkspaceChanged(workspaceChanged);
notifyStatusChanged(status);
}
} else {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
// System.out.println(" ---->>>> WSVM.updateStatus(): scheduling new JOB");
statusRefreshJob.schedule(400);
}
});
}
}
}
private void registerAsListener() {
// ----------------------------------------------------------
// REGISTER for VDB Context changes from VdbViewWorker and fire updateStatus
// ----------------------------------------------------------
// registerWithVdbViewWorker();
// -----------------------------------------------------------
// REGISTER for Resources changes and fire updateStatus when
// resources are added/removed, changed or reloaded
// -----------------------------------------------------------
modelResourceListener = new EventObjectListener() {
@Override
public void processEvent( EventObject obj ) {
final ModelResourceEvent event = (ModelResourceEvent)obj;
final IResource file = event.getResource();
if (event.getType() == ModelResourceEvent.ADDED || event.getType() == ModelResourceEvent.CHANGED
|| event.getType() == ModelResourceEvent.RELOADED || event.getType() == ModelResourceEvent.REMOVED) {
// System.out.println(" WebServicesValidationManager.processEvent() calling updateStatus()");
updateStatus(false);
}
}
};
try {
org.teiid.designer.ui.UiPlugin.getDefault().getEventBroker().addListener(ModelResourceEvent.class,
modelResourceListener);
} catch (EventSourceException e) {
AdvisorUiConstants.UTIL.log(IStatus.ERROR, e, e.getMessage());
}
// -----------------------------------------------------------
// REGISTER for Resources Changes changes and fire updateStatus when
// deltas relating to vdb resources have changed
// -----------------------------------------------------------
resourceListener = new MarkerDeltaListener();
ModelerCore.getWorkspace().addResourceChangeListener(resourceListener);
}
// Listener methods
public void addListener( StatusListener listener ) {
if (statusListeners == null) {
statusListeners = new ArrayList();
}
statusListeners.add(listener);
// System.out.println(" WebServicesValidationManager.addListener() calling updateStatus()");
updateStatus(false);
}
public void removeListener( StatusListener listener ) {
if (statusListeners == null) {
statusListeners = new ArrayList();
}
statusListeners.remove(listener);
if (!statusListeners.isEmpty()) {
// System.out.println(" WebServicesValidationManager.removeListener() calling updateStatus()");
updateStatus(false);
}
}
void notifyStatusChanged( ModelProjectStatus status ) {
this.currentStatus = status;
if (shouldNotify()) {
for (Iterator iter = statusListeners.iterator(); iter.hasNext();) {
((StatusListener)iter.next()).notifyStatusChanged(status);
}
}
}
private boolean shouldNotify() {
boolean result = AdvisorStatusManager.statusEnabled();
// if (statusListeners != null && !statusListeners.isEmpty()) {
// // Check the workbench state
// WorkbenchState state = ProductCustomizerMgr.getInstance().getProductCharacteristics().getWorkbenchState();
// if (state.isStandard() || state.isStartingUp() && viewWorker != null) {
// if (viewWorker.isVdbOpen() && viewWorker.getCurrentVdbContext().getVirtualDatabase() != null) {
// result = true;
// } else if (!viewWorker.isVdbOpen()) {
// result = true;
// }
// }
// }
return result;
}
/**
* Need to be wired up to the current VDB Context.
*
* @see org.teiid.core.designer.event.IChangeListener#stateChanged(org.teiid.core.designer.event.IChangeNotifier)
* @since 5.0
*/
@Override
public void stateChanged( IChangeNotifier theSource ) {
// Just update, don't worry about state of context because updateStatus() will take care of changes
// System.out.println(" WebServicesValidationManager.stateChanged() calling updateStatus()");
updateStatus(false);
}
// Helper methods
private final class MarkerDeltaListener implements IResourceChangeListener {
@Override
public void resourceChanged( IResourceChangeEvent event ) {
// TODO find out if this handles both the enterprise and lightweight cases.
boolean refreshNeeded = false;
IMarkerDelta[] markerDeltas = event.findMarkerDeltas(IMarker.PROBLEM, true);
List<IMarkerDelta> changes = new ArrayList<IMarkerDelta>(markerDeltas.length);
examineDelta(markerDeltas, changes);
if (markerDeltas.length != changes.size()) {
refreshNeeded = true;
}
// Refresh everything if markers were added or removed
if (refreshNeeded) {
// System.out.println(" WebServicesValidationManager.resourceChanged(MARKERS) calling updateStatus()");
updateStatus(false);
} // endif
}
private void examineDelta( IMarkerDelta[] deltas,
List changes ) {
for (int idx = 0; idx < deltas.length; idx++) {
IMarkerDelta delta = deltas[idx];
int kind = delta.getKind();
if (kind == IResourceDelta.CHANGED) {
changes.add(deltas[idx].getMarker());
} // endif
} // endfor
}
} // endclass MarkerDeltaListener
/**
* Method for plugin to call during stop() so this class can unregister itself as a listener.
*
* @since 4.3
*/
public void dispose() {
ModelerCore.getWorkspace().removeResourceChangeListener(resourceListener);
try {
UiPlugin.getDefault().getEventBroker().removeListener(ModelResourceEvent.class, modelResourceListener);
} catch (EventSourceException e) {
AdvisorUiConstants.UTIL.log(IStatus.ERROR, e, e.getMessage());
}
}
/**
* @return Returns the currentStatus.
* @since 4.3
*/
public ModelProjectStatus getCurrentStatus() {
return this.currentStatus;
}
ModelProjectStatus generateNewStatus() {
ModelProjectStatus status = null;
// if (viewWorker.isVdbOpen()) {
// // helper.setVdbContext(viewWorker.getCurrentVdbContext());
// // System.out.println(" >>>>>> WSVM.generateNewStatus(): Asking Helper for NEW WebServiceStatus: VDB = " +
// // helper.getVdbContext().getVirtualDatabase().getName());
// status = helper.getCurrentStatus();
// } else {
helper.setCurrentProject(getCurrentProject());
status = helper.getCurrentStatus();
// }
// System.out.println(" <<<<<< WSVM.generateNewStatus(): DONE ---------------------------");
return status;
}
/**
* Utility method to get a snapshot status of the current Vdb Context.
*
* @return
* @since 5.0
*/
public ModelProjectStatus getStatusSnapshot() {
ModelProjectStatus status = null;
// if (viewWorker.isVdbOpen()) {
// helper.setVdbContext(viewWorker.getCurrentVdbContext());
// status = helper.getCurrentStatus();
// } else {
// helper.setVdbContext(null);
status = helper.getCurrentStatus();
// }
return status;
}
/**
* This method checks the job manager to determine if there is already a job in the QUEUE or not. We don't want more than ONE
* job in the queue (i.e. NOT running) so we don't do too much validation.
*
* @return
* @since 5.0
*/
private boolean shouldAddJob() {
boolean result = false;
Job[] wsJobs = Platform.getJobManager().find(FAMILY_MODEL_PROJECT_STATUS);
int nJobs = wsJobs.length;
if (JobUtils.jobIsRunning(FAMILY_MODEL_PROJECT_STATUS)) {
// If Job is running, only return TRUE if there is Only One Job. If there are more than one, then
// there is already a queued job, so FALSE is OK
if (nJobs == 1) {
result = true;
}
} else if (nJobs == 0) {
// If NO Job is running, only return TRUE if there are NO Jobs in the queue.
result = true;
}
return result;
}
// /////////////////////////////////////////////////////////////////////////////////////////////
// JobListener INNER CLASSes
// /////////////////////////////////////////////////////////////////////////////////////////////
private class AutoBuildJobListener extends JobChangeAdapter {
//
// methods
//
@Override
public void done( IJobChangeEvent theEvent ) {
if (!JobUtils.validationJobsExist() && theEvent.getJob().getName().equals(AUTOBUILD_JOB_NAME)) {
// System.out.println(" AutoBuildJobListener.done(): ##### validation Finished. ##### AUTOBUILD = " +
// ModelerCore.getWorkspace().isAutoBuilding());
updateStatus(false);
isListeningForBuildComplete = false;
}
}
}
//
// Inner class
//
private final class StatusUpdateJob extends Job {
private boolean contextChanged;
// constructors:
StatusUpdateJob( String name ) {
super(name);
setUser(false);
setSystem(true);
}
// Implementation of abstract methods:
@Override
protected IStatus run( IProgressMonitor monitor ) {
// let's wire this job up to listen for vdb context change events
ModelProjectStatus status = generateNewStatus();
// Only we know about the last context, so we need to set the flag to allow the listeners
// that knowledge
if (status != null) {
// status.setContextChanged(contextChanged);
notifyStatusChanged(status);
}
return Status.OK_STATUS;
}
@Override
public boolean belongsTo( Object family ) {
return family == FAMILY_MODEL_PROJECT_STATUS;
}
public void setContextChanged( boolean theContextChanged ) {
contextChanged = theContextChanged;
}
}
/**
* @return currentProject
*/
public IProject getCurrentProject() {
if( this.currentProject != null && !this.currentProject.exists() ) {
this.currentProject = null;
}
return this.currentProject;
}
/**
* Sets the current model project to calculate status on.
*
* @param nextCurrentProject Sets currentProject to the specified value.
* @return true if project was changed, false if not
*/
public boolean setCurrentProject( IProject nextCurrentProject ) {
boolean projectChanged = false;
IProject currentProject = getCurrentProject();
if ((currentProject == null && nextCurrentProject != null) || (currentProject != null && nextCurrentProject == null)) {
projectChanged = true;
} else if (currentProject == null && nextCurrentProject == null) {
projectChanged = false;
} else if (!currentProject.getName().equalsIgnoreCase(nextCurrentProject.getName())) {
projectChanged = true;
}
this.currentProject = nextCurrentProject;
return projectChanged;
}
public static void enable(boolean value) {
enabled = value;
}
public static boolean statusEnabled() {
return enabled;
}
}