blob: e7a5c582e9848ce8a16960bd054089be5a896dcb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2005 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.jem.internal.beaninfo.adapters;
import java.util.logging.Level;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.*;
import org.eclipse.jem.internal.beaninfo.core.BeaninfoPlugin;
import org.eclipse.jem.util.logger.proxy.Logger;
/**
* This class is used by BeaninfoNature to handle the creation of the registry,
* This class will be a singleton. It is needed to handle if UI active without
* requiring UI plugin. (So headless will work too). The subclass <code>UICreateRegistryJobHandler</code>
* will be instantiated in case of UI active.
* @since 1.0.0
*/
class CreateRegistryJobHandler {
private static CreateRegistryJobHandler jobHandler = null;
public static void createRegistry(BeaninfoNature nature) {
synchronized (CreateRegistryJobHandler.class) {
if (jobHandler == null) {
if (Platform.getBundle("org.eclipse.ui") != null) { //$NON-NLS-1$
try {
// There is a UI, it may not be active, but bring in UICreateRegistryJobHandler to do the
// actual work since it can reference the UI.
jobHandler = (CreateRegistryJobHandler) Class.forName("org.eclipse.jem.internal.beaninfo.adapters.UICreateRegistryJobHandler").newInstance(); //$NON-NLS-1$
} catch (InstantiationException e) {
jobHandler = new CreateRegistryJobHandler();
} catch (IllegalAccessException e) {
jobHandler = new CreateRegistryJobHandler();
} catch (ClassNotFoundException e) {
jobHandler = new CreateRegistryJobHandler();
}
}
}
}
// See if Autobuild sleeping or waiting. This could be a race condition for us. We can't wait for it
// because we may already have the build rule locked by our thread. No way of testing this if beginRule was used.
// We can test if we are a build job (not an inline build), and if so, just go on.
// Maybe we can figure out in future if we find race condition happens significant amount of time.
IJobManager jobManager = Job.getJobManager();
Job currentJob = jobManager.currentJob();
if (currentJob == null || (!currentJob.belongsTo(ResourcesPlugin.FAMILY_AUTO_BUILD) && !currentJob.belongsTo(ResourcesPlugin.FAMILY_MANUAL_BUILD))) {
// See if autojob is waiting or sleeping.
// Give it up to a second at .2 second intervals to try (i.e. 5 tries)
int tries = 5;
while (isAutoWaiting() && --tries>0) {
try {
Thread.sleep(200); // Wait just .2 seconds to give build a chance to start. If it is still not started, then just go on.
} catch (InterruptedException e) {
}
}
if (tries==0) {
Logger logger = BeaninfoPlugin.getPlugin().getLogger();
if (logger.isLoggingLevel(Level.WARNING))
logger.log("Build job waiting when trying to start beaninfo registry. Possible race.", Level.WARNING); // $NON-NLS-1$ //$NON-NLS-1$
}
}
jobHandler.processCreateRegistry(nature);
}
private static boolean isAutoWaiting() {
Job[] autojobs = Job.getJobManager().find(ResourcesPlugin.FAMILY_AUTO_BUILD);
for (int i = 0; i < autojobs.length; i++) {
int state = autojobs[i].getState();
if (state == Job.WAITING || state == Job.SLEEPING)
return true;
}
return false;
}
/**
* Process the create of the registry. This should be overridden to
* do what the UI needs. The UI implimentation should call doCreateRegistry at the
* appropriate time.
*
* @param nature
*
* @since 1.0.0
*/
protected void processCreateRegistry(final BeaninfoNature nature) {
IJobManager jobManager = Job.getJobManager();
ISchedulingRule buildRule = ResourcesPlugin.getWorkspace().getRuleFactory().buildRule();
boolean gotRuleLocally = true;
try {
try {
jobManager.beginRule(buildRule, new NullProgressMonitor());
} catch (IllegalArgumentException e) {
gotRuleLocally = false; // This thread already had a rule, and it conflicted with the build rule, so we need to spawn off.
}
if (gotRuleLocally)
doCreateRegistry(nature, new NullProgressMonitor());
} finally {
jobManager.endRule(buildRule); // Whether we got the rule or not, we must do endrule.
}
if (!gotRuleLocally) {
// Spawn off to a job and wait for it. Hopefully we don't have a deadlock somewhere.
Job doCreateJob = new Job(BeanInfoAdapterMessages.UICreateRegistryJobHandler_StartBeaninfoRegistry) {
protected IStatus run(IProgressMonitor monitor) {
doCreateRegistry(nature, monitor);
return Status.OK_STATUS;
}
};
doCreateJob.schedule();
while (true) {
try {
doCreateJob.join();
break;
} catch (InterruptedException e) {
}
}
}
}
/*
* Do the creation. It is expected that the build rule has already been given to this thread.
* It is important that the build rule be given to this thread. This is so that a build won't
* start trying to create the same registry (which has happened in the past) at the same time
* a different thread was trying to start the registry. You would either have a deadlock, or
* a race and get two different registries started.
*
* The build rule also means that all beaninfo registry creations will be serialized and have
* a race condition. The unfortunate part is that two independent project's registries can't be
* created at same time. But that is the result of the build rule. We can't allow the builds, so
* we need to stop all parallel beaninfo registry creations.
*
* @param nature
* @param pm
*
* @since 1.0.0
*/
protected final void doCreateRegistry(BeaninfoNature nature, IProgressMonitor pm) {
pm.beginTask("", 100); //$NON-NLS-1$
try {
nature.createRegistry(new SubProgressMonitor(pm, 100));
} finally {
pm.done();
}
}
}