/*******************************************************************************
* Copyright (c) 2016 Red Hat Inc..
* 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:
* Red Hat Incorporated - initial API and implementation
*******************************************************************************/
package org.jboss.tools.openshift.internal.core.server.resources;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
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.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceRuleFactory;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.MultiRule;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.server.core.IServer;
import org.eclipse.wst.server.core.ServerCore;
import org.eclipse.wst.server.core.ServerUtil;
import org.eclipse.wst.server.core.internal.Messages;
import org.eclipse.wst.server.core.internal.Server;
import org.jboss.tools.openshift.core.server.OpenShiftServer;
import org.jboss.tools.openshift.core.server.OpenShiftServerBehaviour;
import org.jboss.tools.openshift.core.server.OpenShiftServerUtils;
import org.jboss.tools.openshift.internal.core.Trace;
public class OpenshiftResourceChangeListener implements IResourceChangeListener {
@Override
public void resourceChanged(IResourceChangeEvent event) {
final IResourceDelta delta = event.getDelta();
if (delta == null)
return;
// ignore clean builds
if (event.getBuildKind() == IncrementalProjectBuilder.CLEAN_BUILD)
return;
// search for changes to any project using a visitor
try {
delta.accept(new IResourceDeltaVisitor() {
@Override
public boolean visit(IResourceDelta visitorDelta) {
IResource resource = visitorDelta.getResource();
// only respond to project changes
if (resource != null && resource instanceof IProject) {
publishHandleProjectChange(visitorDelta, event);
return false;
}
return true;
}
});
} catch (Exception e) {
Trace.error("Error responding to resource change", e);
}
}
private List<IResource> getDeltaResourceChanges(IResourceDelta delta) {
final ArrayList<IResource> changed = new ArrayList<>();
IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() {
@Override
public boolean visit(IResourceDelta delta2) throws CoreException {
// has this deltaResource been changed?
if (delta2.getKind() == IResourceDelta.NO_CHANGE) {
return false;
} else if(delta2.getResource() instanceof IFolder
&& (delta2.getKind() == IResourceDelta.ADDED || delta2.getKind() == IResourceDelta.REMOVED)) {
// only take folders additions and removals into account.
changed.add(delta2.getResource());
} else if (delta2.getResource() instanceof IFile) {
if (delta2.getKind() == IResourceDelta.CHANGED
&& (delta2.getFlags() & IResourceDelta.MARKERS) != 0
&& (delta2.getFlags() & IResourceDelta.CONTENT) == 0
&& (delta2.getFlags() & IResourceDelta.REPLACED) == 0
&& (delta2.getFlags() & IResourceDelta.SYNC) == 0) {
// this resource is effectively a no change
return false;
}
// Still here means delta has changes
changed.add(delta2.getResource());
}
return true;
}
};
try {
delta.accept(visitor);
} catch(CoreException ce) {
// TODO log
}
return changed;
}
protected void publishHandleProjectChange(IResourceDelta delta, IResourceChangeEvent event) {
IProject project = (IProject) delta.getResource();
if (project == null)
return;
List<IResource> changes = getDeltaResourceChanges(delta);
if( changes.size() > 0) {
OpenShiftServer[] servers2 = getPublishRequiredServers(delta);
int size2 = servers2.length;
for (int j = 0; j < size2; j++) {
handleSpecialProjectChange(servers2[j], delta, changes, event);
}
}
}
private OpenShiftServer[] getPublishRequiredServers(IResourceDelta delta){
// The list of servers that will require publish
final List<OpenShiftServer> servers2 = new ArrayList<>();
// wrksServers = Workspaces Servers
final IServer[] wrksServers = ServerCore.getServers();
for( int i = 0; i < wrksServers.length; i++ ) {
OpenShiftServer os = (OpenShiftServer)wrksServers[i].loadAdapter(OpenShiftServer.class, new NullProgressMonitor());
if( os != null ) {
IProject magic = OpenShiftServerUtils.getDeployProject(wrksServers[i]);
if( magic != null ) {
// Safe because we've already eliminated non-project deltas
IProject p = (IProject)delta.getResource();
if( magic.equals(p)) {
servers2.add(os);
}
}
}
}
return (OpenShiftServer[]) servers2.toArray(new OpenShiftServer[servers2.size()]);
}
protected void handleSpecialProjectChange(OpenShiftServer server, IResourceDelta delta, List<IResource> changes, IResourceChangeEvent event) {
// check for duplicate jobs already waiting and don't create a new one
Job[] jobs = Job.getJobManager().find(ServerUtil.SERVER_JOB_FAMILY);
if (jobs != null) {
int size = jobs.length;
for (int i = 0; i < size; i++) {
if (jobs[i] instanceof MagicProjectChangeJob) {
MagicProjectChangeJob rcj = (MagicProjectChangeJob) jobs[i];
if (rcj.getServer().equals(server.getServer()) && rcj.getState() == Job.WAITING)
return;
}
}
}
MagicProjectChangeJob job = new MagicProjectChangeJob(server, delta, changes, event);
job.setSystem(true);
job.setPriority(Job.BUILD);
job.schedule();
}
/**
* Give the server an indication that its magic project has been changed somehow
*/
public class MagicProjectChangeJob extends Job {
private IResourceDelta delta;
private OpenShiftServer openshiftServer;
private IResourceChangeEvent event;
private List<IResource> changes;
public MagicProjectChangeJob(OpenShiftServer openshiftServer, IResourceDelta delta, List<IResource> change, IResourceChangeEvent event) {
super(NLS.bind(Messages.jobUpdateServer, openshiftServer.getServer().getName()));
this.openshiftServer = openshiftServer;
this.delta = delta;
this.changes = change;
this.event = event;
ISchedulingRule[] rules = new ISchedulingRule[2];
IResourceRuleFactory ruleFactory = ResourcesPlugin.getWorkspace().getRuleFactory();
rules[0] = ruleFactory.createRule(delta.getResource());
rules[1] = openshiftServer.getServer();
setRule(MultiRule.combine(rules));
}
@Override
public boolean belongsTo(Object family) {
return ServerUtil.SERVER_JOB_FAMILY.equals(family);
}
public IServer getServer() {
return openshiftServer.getServer();
}
@Override
protected IStatus run(IProgressMonitor monitor) {
IServer server = openshiftServer.getServer();
OpenShiftServerBehaviour behaviourDelegate = (OpenShiftServerBehaviour)
server.loadAdapter(OpenShiftServerBehaviour.class, new NullProgressMonitor());
int oldState = server.getServerPublishState();
int newState = ((oldState == IServer.PUBLISH_STATE_FULL || oldState == IServer.PUBLISH_STATE_UNKNOWN)
? IServer.PUBLISH_STATE_FULL : IServer.PUBLISH_STATE_INCREMENTAL);
((Server)server).setServerPublishState(newState);
if (server.getServerState() != IServer.STATE_STOPPED && behaviourDelegate != null)
behaviourDelegate.handleResourceChange();
if (server.getServerState() == IServer.STATE_STARTED)
autoPublish(event);
return Status.OK_STATUS;
}
private void autoPublish(IResourceChangeEvent event) {
boolean buildOccurred = event != null && didBuildOccur(event);
boolean projectClosedOrDeleted = event != null && isProjectCloseOrDeleteEvent(event);
int auto = ((Server)openshiftServer.getServer()).getAutoPublishSetting();
if (auto == Server.AUTO_PUBLISH_DISABLE)
return;
if( (auto == Server.AUTO_PUBLISH_BUILD) &&
!buildOccurred && !projectClosedOrDeleted)
return;
int time = ((Server)openshiftServer.getServer()).getAutoPublishTime();
if (time >= 0) {
openshiftServer.getServer().publish(IServer.PUBLISH_INCREMENTAL,
new NullProgressMonitor());
}
}
private boolean isProjectCloseOrDeleteEvent(IResourceChangeEvent event) {
int kind = event.getType();
if( (kind & IResourceChangeEvent.PRE_CLOSE) > 0 ||
(kind & IResourceChangeEvent.PRE_DELETE) > 0)
return true;
return false;
}
private boolean didBuildOccur(IResourceChangeEvent event) {
int kind = event.getBuildKind();
final boolean eventOccurred =
(kind == IncrementalProjectBuilder.INCREMENTAL_BUILD) ||
(kind == IncrementalProjectBuilder.FULL_BUILD) ||
((kind == IncrementalProjectBuilder.AUTO_BUILD &&
ResourcesPlugin.getWorkspace().isAutoBuilding()));
return eventOccurred;
}
}
}